static_assert 依赖于非类型模板参数(gcc 和 clang 的行为不同)

static_assert dependent on non-type template parameter (different behavior on gcc and clang)

template <int answer> struct Hitchhiker {
  static_assert(sizeof(answer) != sizeof(answer), "Invalid answer");
};

template <> struct Hitchhiker<42> {};

在尝试使用 static_assert 禁用通用模板实例化时,我发现即使模板未实例化,clang 中的上述代码也会生成断言错误,而 gcc 生成仅在使用 42.

以外的参数实例化 Hitchhiker 时断言错误

摆弄我发现这个断言:

template <int answer> struct Hitchhiker {
  static_assert(sizeof(int[answer]) != sizeof(int[answer]), "Invalid answer");
};

template <> struct Hitchhiker<42> {};

在两个编译器上的行为相同:断言仅在实例化通用模板时启动。

标准是怎么说的,哪个编译器是正确的?

g++ 4.9.2
clang++ 3.50

两个编译器都是正确的。来自 [temp.res]/8:

If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required.

不存在可以从主模板 Hitchhiker 生成的有效专业化,因此它的格式不正确,不需要诊断。 clang 仍然选择发出诊断。

如果只想允许42,那么干脆不要定义通用模板:

template <int > struct Hitchhiker;
template <> struct Hitchhiker<42> {};

@TartainLlama 找到的语录

If a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, the program is ill-formed; no diagnostic is required.

N4296 [temp.res]/8

这在定义主模板(其中包含 static_assert 的模板)后立即应用。所以后面的特化(for 42)不能考虑,因为它还不存在。

下一个问题是 static_assert( sizeof(answer) != sizeof(answer), 是否依赖于 answer。语义上不是,语法上是,标准方面:

Inside a template, some constructs have semantics which may differ from one instantiation to another. Such a construct depends on the template parameters.

N4296 [temp.dep]/1

sizeof(answer) != sizeof(answer) 的构造在一个实例化与另一个实例化之间没有区别。所以这样的构造 不依赖于 模板参数。这意味着整个 static_assert 不依赖于模板参数。

因此您的程序格式错误,不需要诊断。发出任意诊断(例如 static_assert 失败)是有效的编译器行为。缺少问题是有效的编译器行为。从格式错误、不需要诊断的程序编译而来的程序的行为不是由标准定义的:它是未定义的行为。允许鼻魔。

花哨的尝试(比如 sizeof(int[answer])!=sizeof(int[answer]) 可能会取悦当前的 god 编译器,但不会使您的程序更完整。

您可能会遇到编译器不太可能捕捉到您的情况,但无论编译器是否能够捕捉到您,格式错误仍然存​​在。作为一般规则,C++ 想让自己(及其编译器)自由地寻找无效的模板代码 "earlier than instantiation";这意味着模板代码必须生成可能合法的代码。

您可能想要 =delete 之类的东西并附加一条消息。