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
2 回答
由@TartainLlama发现的行情
N4296 [temp.res] / 8
这在定义主模板后立即应用(其中包含
static_assert
的模板) . 因此,后来的专业化(对于42
)不能被考虑,因为它还不存在 .接下来的问题是
static_assert( sizeof(answer) != sizeof(answer),
是否取决于answer
. 从语义上讲,它没有,从语法上来说,它是标准的:N4296 [temp.dep] / 1
构造
sizeof(answer) != sizeof(answer)
与一个实例不同 . 所以这样的构造不依赖于模板参数 . 这意味着整个static_assert
不依赖于模板参数 .因此,您的程序形成不良,无需诊断 . 发出任意诊断(例如
static_assert
失败)是有效的编译器行为 . 缺少问题是有效的编译器行为 . 从标准形成的,没有诊断要求的程序编译的程序的行为不是由标准定义的:它是未定义的行为 . 允许鼻腔恶魔 .花哨的尝试(如
sizeof(int[answer])!=sizeof(int[answer])
可能会让当前的神编译器满意,但不会让您的程序更加完善 .你可以提出一个案例,编译器不太可能 grab 你,但不管编译器是否有能力 grab 你,它仍然存在形式错误 . 作为一般规则,C希望让自己(及其编译器)自由地“在实例化之前”找到无效的模板代码;这意味着模板代码必须生成可能合法的代码 .
您可能需要附带消息的
=delete
之类的内容 .两个编译器都是正确的 . 来自[temp.res] / 8:
不存在可从主模板
Hitchhiker
生成的有效专业化,因此它格式错误,无需诊断 . clang无论如何选择发布诊断 .如果您只想允许
42
,那么只需不要定义通用模板: