为什么尽管使用了 C++14 功能,但使用 C++11 编译还是成功的?
Why compiling with C++11 is successful despite using C++14 feature?
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]
如果这是仅在 C++14 中可用的功能,为什么它可以使用 C++11 标志进行编译并且我可以 运行 可执行文件?不应该是致命错误吗?
无"should be a fatal error"。如果编译器写了一条消息告诉你发生了什么,它就完成了它的义务。
您现在可以自由地决定是否将代码视为具有致命错误并更改代码;或将其视为 C++14 并使用它。
如果您觉得有帮助,可以使用开关 -Werror
(将消息中的单词 "warning" 更改为 "error")。
C++标准没有"fatal compiler error"的概念。程序要么格式错误且需要诊断,要么格式错误且不需要诊断,要么格式正确。
在 C++ 中,标准对格式错误的程序诊断的唯一要求是显示诊断1。该诊断的内容未定义。除了未定义诊断之外还会发生什么。
许多编译器实现了 C++ 标准的扩展,他们被告知要针对这些标准进行编译,这些标准采用其他格式错误的程序并生成可运行的可执行文件。如果它们符合标准,它们唯一要做的就是打印警告消息(满足 C++ 标准的诊断要求)。
在这种情况下,它会打印一条警告消息,表明您使用了 C++14 功能。它现在已经成功地完成了 C++11 标准对格式错误的程序的要求。它还会生成一个可执行文件,如果使用 C++14 标准中的该功能,它会执行您的程序将执行的操作:这样做是免费的,因为此时的标准对程序的操作没有任何限制,一旦它是一个格式错误的 C++11 程序。
如果您不想要这个选项,编译器通常有一个 warnings-as-errors
标志,以及各种 strict
和 pedantic
标志,这些标志阻止对他们使用的标准的扩展。然后错误会抑制生成可执行文件,你就不会再迷茫了。
gcc 默认假定您确实想将提供的代码编译成某种东西,而不是充当标准执行者,并且仅当它没有合理的方式将您的代码解释为可能与您的程序匹配的程序时才会产生错误意图。它提供标志以将其切换到严格和迂腐的模式。
1 有趣的是,打印出单个 space 字符就可以满足显示诊断的要求。可以以病态的方式阅读 C++ 标准,以便在编译器中生成质量较差的实现:生成一个敌对的编译器证明标准是不值得的。
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]
如果这是仅在 C++14 中可用的功能,为什么它可以使用 C++11 标志进行编译并且我可以 运行 可执行文件?不应该是致命错误吗?
无"should be a fatal error"。如果编译器写了一条消息告诉你发生了什么,它就完成了它的义务。
您现在可以自由地决定是否将代码视为具有致命错误并更改代码;或将其视为 C++14 并使用它。
如果您觉得有帮助,可以使用开关 -Werror
(将消息中的单词 "warning" 更改为 "error")。
C++标准没有"fatal compiler error"的概念。程序要么格式错误且需要诊断,要么格式错误且不需要诊断,要么格式正确。
在 C++ 中,标准对格式错误的程序诊断的唯一要求是显示诊断1。该诊断的内容未定义。除了未定义诊断之外还会发生什么。
许多编译器实现了 C++ 标准的扩展,他们被告知要针对这些标准进行编译,这些标准采用其他格式错误的程序并生成可运行的可执行文件。如果它们符合标准,它们唯一要做的就是打印警告消息(满足 C++ 标准的诊断要求)。
在这种情况下,它会打印一条警告消息,表明您使用了 C++14 功能。它现在已经成功地完成了 C++11 标准对格式错误的程序的要求。它还会生成一个可执行文件,如果使用 C++14 标准中的该功能,它会执行您的程序将执行的操作:这样做是免费的,因为此时的标准对程序的操作没有任何限制,一旦它是一个格式错误的 C++11 程序。
如果您不想要这个选项,编译器通常有一个 warnings-as-errors
标志,以及各种 strict
和 pedantic
标志,这些标志阻止对他们使用的标准的扩展。然后错误会抑制生成可执行文件,你就不会再迷茫了。
gcc 默认假定您确实想将提供的代码编译成某种东西,而不是充当标准执行者,并且仅当它没有合理的方式将您的代码解释为可能与您的程序匹配的程序时才会产生错误意图。它提供标志以将其切换到严格和迂腐的模式。
1 有趣的是,打印出单个 space 字符就可以满足显示诊断的要求。可以以病态的方式阅读 C++ 标准,以便在编译器中生成质量较差的实现:生成一个敌对的编译器证明标准是不值得的。