Відповідь складається з двох частин. Сумісність на рівні компілятора та сумісність на рівні лінкера. Почнемо з першого.
припустимо, всі заголовки написані на C ++ 11
Використання одного і того ж компілятора означає, що будуть використовуватися однакові стандартні заголовки бібліотеки та вихідні файли (ті, що пов'язані з компілятором), незалежно від цільового стандарту C ++. Отже, файли заголовків стандартної бібліотеки написані для сумісності з усіма версіями С ++, що підтримуються компілятором.
Тим не менш, якщо параметри компілятора, що використовуються для компіляції блоку перекладу, визначають конкретний стандарт C ++, то будь-які функції, доступні лише в нових стандартах, не повинні бути доступними. Це робиться за допомогою __cplusplus
директиви. Дивіться векторний вихідний файл для цікавого прикладу того, як він використовується. Подібним чином компілятор відкине будь-які синтаксичні особливості, пропоновані новішими версіями стандарту.
Все це означає, що ваше припущення може стосуватися лише файлів заголовків, які ви написали. Ці заголовкові файли можуть спричинити несумісність, якщо вони включені в різні блоки перекладу, орієнтовані на різні стандарти C ++. Це обговорюється в додатку С до стандарту С ++. Є 4 речення, я обговорю лише перший, а коротко згадаю решту.
C.3.1 Пункт 2: лексичні умовні позначення
Поодинокі лапки розмежовують символьний літерал у C ++ 11, тоді як вони є роздільниками цифр у C ++ 14 та C ++ 17. Припустимо, у вас є таке визначення макросу в одному із чистого заголовного файлу C ++ 11:
#define M(x, ...) __VA_ARGS__
int x[2] = { M(1'2,3'4) };
Розглянемо дві одиниці перекладу, які включають файл заголовка, але цільові C ++ 11 та C ++ 14, відповідно. При націлюванні на C ++ 11 кома в лапках не вважається роздільником параметрів; параметр є лише один раз. Тому код буде еквівалентний:
int x[2] = { 0 };
З іншого боку, при націлюванні на C ++ 14, одинарні лапки інтерпретуються як роздільники цифр. Тому код буде еквівалентний:
int x[2] = { 34, 0 };
Справа тут у тому, що використання одинарних лапок в одному із чистих файлів заголовків C ++ 11 може призвести до дивовижних помилок у одиницях перекладу, націлених на C ++ 14/17. Отже, навіть якщо файл заголовка написаний на C ++ 11, він повинен бути написаний обережно, щоб переконатися, що він сумісний з пізнішими версіями стандарту. __cplusplus
Директива може бути корисним тут.
Інші три статті стандарту включають:
С.3.2 Пункт 3: основні поняття
Зміна : Новий звичайний (не розміщений) дилокатор
Обґрунтування : Потрібно для розміщення великих розмірів.
Вплив на оригінальну функцію : дійсний код C ++ 2011 може оголосити глобальну функцію розподілу розміщення та функцію звільнення таким чином:
void operator new(std::size_t, std::size_t);
void operator delete(void*, std::size_t) noexcept;
Однак у цьому міжнародному стандарті декларація видалення оператора може збігатися із заздалегідь визначеним звичайним (не розміщенням) оператором видалення (3.7.4). Якщо так, програма неправильно сформована, як це було для функцій розподілу членів класу та функцій звільнення (5.3.4).
C.3.3 Пункт 7: декларації
Зміна : нестатичні функції-члени constexpr не є неявними функціями-членами.
Обґрунтування : Необхідно дозволити функціям-членам constexpr мутувати об'єкт.
Вплив на оригінальну функцію : Діючий код C ++ 2011 може не скомпілюватись у цьому міжнародному стандарті.
Наприклад, такий код є дійсним у C ++ 2011, але недійсним у цьому міжнародному стандарті, оскільки він двічі оголошує одну і ту ж функцію-член із різними типами повернення:
struct S {
constexpr const int &f();
int &f();
};
C.3.4 Пункт 27: Бібліотека вводу / виводу
Зміна : отримує не визначено.
Обґрунтування : Використання отримувачів вважається небезпечним.
Вплив на оригінальну особливість : дійсний код C ++ 2011, який використовує функцію get, може не вдатися до компіляції в цьому міжнародному стандарті.
Потенційні несумісності між C ++ 14 і C ++ 17 обговорюються в C.4. Оскільки всі нестандартні файли заголовків написані на C ++ 11 (як зазначено у питанні), ці проблеми не виникатимуть, тому я не буду їх тут згадувати.
Зараз я обговорю сумісність на рівні компонувальника. Загалом, потенційні причини несумісності включають наступне:
- Формат об'єктних файлів.
- Програмуйте процедури запуску та завершення та
main
точку входу.
- Оптимізація цілої програми (WPO).
Якщо формат результуючого об'єктного файлу залежить від цільового стандарту C ++, компонувальник повинен мати можливість зв'язувати різні об'єктні файли. У країнах GCC, LLVM та VC ++ це, на щастя, не так. Тобто формат файлів об’єктів однаковий, незалежно від цільового стандарту, хоча він сильно залежить від самого компілятора. Насправді жоден з компонувальників GCC, LLVM та VC ++ не потребує знань про цільовий стандарт C ++. Це також означає, що ми можемо зв'язати об'єктні файли, які вже скомпільовані (статично пов'язуючи час виконання).
Якщо підпрограма запуску програми (функція, яка викликає main
) відрізняється для різних стандартів C ++ і різні підпрограми не сумісні між собою, тоді неможливо буде зв’язати об’єктні файли. У країнах GCC, LLVM та VC ++ це, на щастя, не так. Крім того, підпис main
функції (та обмеження, що застосовуються до неї, див. Розділ 3.6 стандарту) однаковий у всіх стандартах С ++, тому не має значення, в якій одиниці перекладу вона існує.
Загалом, WPO може погано працювати з об'єктними файлами, скомпільованими з використанням різних стандартів C ++. Це залежить від того, які саме етапи компілятора вимагають знання цільового стандарту, а які - ні, та вплив, який він робить на міжпроцедурну оптимізацію, яка перетинає об’єктні файли. На щастя, GCC, LLVM та VC ++ добре розроблені і не мають цієї проблеми (не те, що мені відомо).
Тому GCC, LLVM та VC ++ були розроблені, щоб забезпечити двійкову сумісність у різних версіях стандарту C ++. Однак це насправді не є вимогою самого стандарту.
До речі, хоча компілятор VC ++ пропонує перемикач std , який дозволяє націлювати певну версію стандарту C ++, він не підтримує націлювання на C ++ 11. Мінімальною версією, яку можна вказати, є C ++ 14, яка за замовчуванням починається з оновлення Visual C ++ 2013 3. Для націлювання на C ++ 11 можна використовувати стару версію VC ++, але тоді вам доведеться використовувати різні компілятори VC ++ компілювати різні одиниці перекладу, орієнтовані на різні версії стандарту С ++, що як мінімум порушить WPO.
CAVEAT: Моя відповідь може бути не повною або дуже точною.