bol*_*lov 25 c++ templates dependent-name language-lawyer c++14
template <int answer> struct Hitchhiker {
static_assert(sizeof(answer) != sizeof(answer), "Invalid answer");
};
template <> struct Hitchhiker<42> {};
Run Code Online (Sandbox Code Playgroud)
在尝试禁用常规模板实例化的同时,static_assert我发现clang即使模板未实例化,上面的代码也会生成断言错误,而gcc只有在Hitchhiker使用除了以外的参数进行实例化时才生成断言错误42.
摆弄我发现这个断言:
template <int answer> struct Hitchhiker {
static_assert(sizeof(int[answer]) != sizeof(int[answer]), "Invalid answer");
};
template <> struct Hitchhiker<42> {};
Run Code Online (Sandbox Code Playgroud)
两个编译器的行为相同:只有在实例化通用模板时,断言才会启动.
标准说什么,哪个编译器是对的?
g++ 4.9.2
clang++ 3.50
Run Code Online (Sandbox Code Playgroud)
Bar*_*rry 15
两个编译器都是正确的.来自[temp.res]/8:
如果无法为模板生成有效的专业化,并且未实例化该模板,则模板格式错误,无需诊断.
没有可以从主模板生成的有效专业化Hitchhiker,因此它格式错误,无需诊断.clang无论如何选择发布诊断.
如果您只想允许42,那么只需不要定义通用模板:
template <int > struct Hitchhiker;
template <> struct Hitchhiker<42> {};
Run Code Online (Sandbox Code Playgroud)
Yak*_*ont 14
@TartainLlama发现的行情
如果由于不依赖于模板参数的构造而导致紧接其定义之后的模板的假设实例化是不正确的,则该程序是不正确的; 无需诊断.
N4296 [temp.res]/8
这在定义主模板后立即应用(包含其中的模板static_assert).因此,后来的专业化(for 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])可能会喜欢当前的神编译器,但不会使你的程序更好地形成.
你可以提出一个编译器不太可能抓住你的情况,但是不管编译器是否能够抓住你,它仍然存在形式错误.作为一般规则,C++希望让自己(及其编译器)自由地"在实例化之前"找到无效的模板代码; 这意味着模板代码必须生成可能合法的代码.
您可能需要=delete附加消息的内容.