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
之类的东西并附加一条消息。
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
之类的东西并附加一条消息。