Почему компиляция с С++ 11 успешна, несмотря на использование функции С++ 14?

GCC v6.1 (результат тот же с v5.1) успешно компилирует код ниже с флагами -std=c++11 -Wall -Wextra -Wpedantic, но выдает это предупреждение:

variable templates only available with -std=c++14 or -std=gnu++14

Код:

#include <iostream>

template <typename T>
struct ParamMetadata {
        T min;
        T max;
};

template <class T1, class T2>
class FooMap {};

template <typename T>
// WARNING PRODUCED ON THIS LINE
extern FooMap<int, ParamMetadata<T> > metadataHashmap;

int main() {
        return 0;
}

Clang v3.8 создает аналогичное предупреждение:

variable templates are a C++14 extension [-Wc++14-extensions]

Если это функция, доступная только в С++ 14, почему она скомпилирована с флагом С++ 11, и я могу запустить исполняемый файл? Не должно ли это быть фатальной ошибкой?

Ответы

Ответ 1

Стандарт С++ не имеет понятия "фатальная ошибка компилятора". Программы либо плохо сформированы с требуемой диагностикой, либо плохо сформированы без необходимости диагностики или хорошо сформированы.

В С++ единственное требование, которое стандарт помещает в неверно сформированную диагностику программы, - отобразить диагностический 1. Содержимое этой диагностики не определено. Что еще происходит, кроме того, что диагностика не определена.

Многие компиляторы реализуют расширения к стандарту С++, которые, как им говорят, компилируются против других программ с плохой структурой и создают исполняемый исполняемый файл. Если они соответствуют стандарту, единственное, что они должны сделать, это напечатать предупреждающее сообщение (которое удовлетворяет требованиям диагностики стандарта (ов) С++).

В этом случае печатается предупреждающее сообщение о том, что вы использовали функцию С++ 14. Теперь он успешно выполнил то, что требует стандарт С++ 11 с вашей плохо сформированной программой. Он также создает исполняемый файл, который делает то, что будет делать ваша программа, если бы использовалась эта функция из стандарта С++ 14: она свободна в этом, так как стандарт в этот момент не содержит ограничений на то, что программа делает, плохо сформированная программа С++ 11.

Если вы не хотите эту опцию, у компиляторов часто есть флаг warnings-as-errors и различные флаги strict и pedantic, которые блокируют расширения до стандарта, который они используют. Тогда ошибка будет подавлять генерацию исполняемого файла, и вы больше не будете путать.

gcc по умолчанию предполагает, что вы действительно хотите скомпилировать предоставленный код во что-то, а не выступать в качестве стандартного исполнителя, и генерировать ошибки только тогда, когда у него нет разумного способа интерпретировать ваш код как программу, которая, вероятно, соответствует вашим намерениям. Он предоставляет флаги для переключения на строгий и педантичный режим.


1 Смешно, распечатывая один пробел, удовлетворяет требование отображать диагностику. Стандарт С++ может быть прочитан патологическими способами, чтобы создать низкое качество реализации в вашем компиляторе: генерация нестойкого стандарта, не требующего усилий для компилятора, не стоит усилий.

Ответ 2

Ничего "не должно быть фатальной ошибкой". Если компилятор пишет сообщение о том, что произошло, он выполнил свои обязательства.

Теперь вы можете принять полное обоснованное решение о том, следует ли рассматривать код как фатальную ошибку и изменить код; или рассматривать его так, как если бы он был С++ 14 и идти с ним.

Вы можете использовать переключатель -Werror (меняет слово "предупреждение" на "ошибка" в сообщении), если вы считаете, что это поможет.