为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C++
慕侠2389804 2019-11-20 09:35:56
template <int answer> struct Hitchhiker {  static_assert(sizeof(answer) != sizeof(answer), "Invalid answer");};template <> struct Hitchhiker<42> {};在尝试使用禁用常规模板实例化时,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> {};在两个编译器上的行为相同:断言仅在实例化常规模板时才起作用。标准说什么,哪个编译器正确?g++ 4.9.2clang++ 3.50
查看完整描述

3 回答

?
浮云间

TA贡献1829条经验 获得超4个赞

如果由于不依赖于模板参数的构造而导致模板定义后的假想实例化格式不正确,则程序格式不正确;无需诊断。


N4296 [温度] / 8


这在定义了主模板(其中有一个static_assert)之后立即适用。因此,以后的专业化(for 42)尚不存在,因此无法考虑。


接下来的问题是,如果static_assert( sizeof(answer) != sizeof(answer), 依赖于answer。在语义上没有,在语法上没有,并且在标准方面:


在模板内部,某些构造的语义可能因一个实例而异。这样的构造取决于模板参数。


N4296 [温度深度] / 1


构造sizeof(answer) != sizeof(answer)从一个实例到另一个实例没有不同。因此,这种构造不依赖于模板参数。这意味着整个过程static_assert不取决于template参数。


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


花哨的尝试(例如sizeof(int[answer])!=sizeof(int[answer])可能会喜欢当前的上帝编译器,但不会使您的程序格式更好。


您可能会遇到这样的情况,即编译器不太可能抓住您,但是不管编译器是否能够抓住您,它的格式仍然不正确。通常,C ++希望保留自身(及其编译器)的自由,以“早于实例化”来查找无效的模板代码。这意味着模板代码必须产生可能的合法代码。


您可能想要=delete带有附加消息的内容。


查看完整回答
反对 回复 2019-11-20
?
偶然的你

TA贡献1841条经验 获得超3个赞

两种编译器都是正确的。从[temp.res] / 8:


如果无法为模板生成有效的专业化名称,并且该模板未实例化,则该模板格式错误,无需诊断。


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


如果您只想允许42,则只需不定义常规模板:


template <int > struct Hitchhiker;

template <> struct Hitchhiker<42> {};


查看完整回答
反对 回复 2019-11-20
?
慕桂英4014372

TA贡献1871条经验 获得超13个赞

我不同意您对[temp.dep] / 1的解释:我认为May 可以作为编译器的余地,以避免实际尝试构造一个实例或另一个实例中是否确实具有不同语义的问题,并且相反,让编译器决定是否有可能具有不同的语义(它提到模板参数),则将其视为“ depends”。我认为,这条路非常重要,因为表达式可以任意卷积,从而确定实例化是否可能是复杂的。

查看完整回答
反对 回复 2019-11-20
  • 3 回答
  • 0 关注
  • 626 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信