Ответ состоит из двух частей. Совместимость на уровне компилятора и совместимость на уровне компоновщика. Начнем с первого.
предположим, что все заголовки были написаны на C ++ 11
Использование одного и того же компилятора означает, что одни и те же заголовок стандартной библиотеки и исходные файлы (те, которые связаны с компилятором) будут использоваться независимо от целевого стандарта C ++. Следовательно, файлы заголовков стандартной библиотеки написаны для совместимости со всеми версиями C ++, поддерживаемыми компилятором.
Тем не менее, если параметры компилятора, используемые для компиляции единицы перевода, указывают конкретный стандарт C ++, то любые функции, доступные только в новых стандартах, не должны быть доступны. Это делается с помощью __cplusplus
директивы. Смотрите в исходном векторном файле интересный пример того, как он используется. Точно так же компилятор отклонит любые синтаксические функции, предлагаемые более новыми версиями стандарта.
Все это означает, что ваше предположение применимо только к написанным вами заголовочным файлам. Эти файлы заголовков могут вызывать несовместимость при включении в разные единицы перевода, ориентированные на разные стандарты C ++. Это обсуждается в Приложении C стандарта 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
Директива может быть полезным здесь.
Остальные три пункта стандарта включают:
C.3.2 Раздел 3: основные концепции
Изменение : новый обычный (без размещения) деаллокатор
Обоснование : требуется для освобождения размера.
Влияние на исходную функцию : действующий код C ++ 2011 может объявлять функцию глобального размещения и функцию освобождения следующим образом:
void operator new(std::size_t, std::size_t);
void operator delete(void*, std::size_t) noexcept;
Однако в этом международном стандарте объявление оператора delete может совпадать с предопределенным обычным (без размещения) оператором delete (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, использующий функцию gets, может не соответствовать этому международному стандарту.
Возможная несовместимость между C ++ 14 и C ++ 17 обсуждается в C.4. Поскольку все нестандартные файлы заголовков написаны на C ++ 11 (как указано в вопросе), этих проблем не возникнет, поэтому я не буду их здесь упоминать.
Теперь обсудим совместимость на уровне компоновщика. В общем, потенциальные причины несовместимости включают следующее:
Если формат результирующего объектного файла зависит от целевого стандарта C ++, компоновщик должен иметь возможность связывать различные объектные файлы. К счастью, в GCC, LLVM и VC ++ это не так. То есть формат файлов объектов один и тот же независимо от целевого стандарта, хотя он сильно зависит от самого компилятора. Фактически, ни один из компоновщиков GCC, LLVM и VC ++ не требует знаний о целевом стандарте C ++. Это также означает, что мы можем связывать уже скомпилированные объектные файлы (статически связывая среду выполнения).
Если процедура запуска программы (вызываемая функция main
) отличается для разных стандартов C ++ и разные процедуры несовместимы друг с другом, то связать объектные файлы будет невозможно. К счастью, в GCC, LLVM и VC ++ это не так. Кроме того, сигнатура main
функции (и ограничения, которые применяются к ней, см. Раздел 3.6 стандарта) одинакова для всех стандартов C ++, поэтому не имеет значения, в какой единице перевода она существует.
Как правило, WPO может плохо работать с объектными файлами, скомпилированными с использованием различных стандартов C ++. Это зависит от того, какие именно этапы компилятора требуют знания целевого стандарта, а какие - нет, а также от того, какое влияние он оказывает на межпроцедурные оптимизации, перекрестные с объектными файлами. К счастью, GCC, LLVM и VC ++ хорошо спроектированы и не имеют этой проблемы (насколько мне известно).
Поэтому GCC, LLVM и VC ++ были разработаны для обеспечения двоичной совместимости между различными версиями стандарта C ++. Однако на самом деле это не является требованием самого стандарта.
Кстати, хотя компилятор VC ++ предлагает переключатель std , который позволяет настроить таргетинг на конкретную версию стандарта C ++, он не поддерживает таргетинг на C ++ 11. Минимальная версия, которую можно указать, - C ++ 14, которая используется по умолчанию, начиная с Visual C ++ 2013 Update 3. Вы можете использовать старую версию VC ++ для таргетинга на C ++ 11, но тогда вам придется использовать другие компиляторы VC ++. для компиляции разных единиц перевода, предназначенных для разных версий стандарта C ++, что, по крайней мере, нарушит WPO.
CAVEAT: Мой ответ может быть не полным или очень точным.