C ++ 11 static_assert和模板实例化

在C ++ 11中,模板中的static_assert操作应该取决于该模板是否已经实例化? 例如,用下面的代码

template <int I> void sa() { static_assert(0,"Hello."); } int main(int argc, char *argv[]) { return 0; } 

GCC 4.5.0将失败断言,并产生“你好”。 信息。 另一方面,Digital Mars Compiler版本8.42n没有提供任何消息。

GCC是正确的,另一个编译器也是正确的。 请参阅规格中的14.6p8

如果没有为模板定义生成有效的特化,并且该模板未实例化,则模板定义不合格,不需要诊断。

因此,编译器可以自由地拒绝以下内容

 template<typename T> void f() { static_assert(0, "may trigger immediately!"); static_assert(sizeof(T) == 0, "may trigger immediately!"); } 

如果你想要安全起见,你必须安排它,这样编译器才能知道直到实例化布尔expression式是真还是假。 例如,通过getvalue<T>::valuegetvalue是一个类模板(可以专门化它,所以编译器不可能知道布尔值)。

我相信编译器是在它的权利扩展任何静态断言不依赖于模板参数,而不需要实例 – 但我不认为这是必需的。 请记住,不同的草案标准可能有不同的规则,可能会发生这种情况。

C ++ 0x草案( N3242 )在14.6p8中说:

“如果没有为模板定义生成有效的专业化,并且该模板没有实例化,则模板定义不合格,不需要进行诊断。

C ++ 03标准中出现了相同的词汇。

在这个问题的例子中,这个模板没有有效的实例化,所以引用的措辞是适用的。

由于不需要诊断,如果模板没有实例化,编译器可以编译程序。 当然,如果它被实例化,则该程序是不合格的,需要诊断。

我使用了一个辅助函数来取决于模板参数:

 template<typename T> bool dependentFalse<T>() { return false; } template<typename T> Foo foo() { static_assert(dependentFalse<T>(), "this template shouldn't be instantiated"); } 

这是C ++标准中的14.6.2节。

您的static_assert最初parsing模板时支持绑定非独立名称有关。 Digital Mars Compiler目前不支持绑定非独立名称。 GCC 4.5.0不支持绑定非依赖名称。

如果您的expression式不依赖于模板参数,那么在开始parsing模板时,这种expression式是已知的。 编译器必须显示错误信息。 GCC 4.5.0做到了。

static_assert0replace为I*I < 0 ,用于expample,并获取相关名称。 错误信息将只出现在没有实际模板的情况下。

这个程序产生一个错误:

 template <int I> void sa() { static_assert(0,"Hello."); } template <> void sa<0>() { } int main(int argc, char *argv[]) { return 0; } 

这个程序没有:

 template <int I> void sa() { static_assert(I != 0,"Hello."); } template <> void sa<0>() { } int main(int argc, char *argv[]) { return 0; } 

情况确实如此。 所以我得出这样的结论:如果在一个没有实际意义的模板中触发static_assert ,那么g ++ 4.5必须是错误的。

更麻烦的是,下面的程序打印出I == 1

 #include <iostream> using ::std::cout; template <int I> void sa() { cout << "I == " << I << '\n'; static_assert(I != 0,"Hello."); } template <> void sa<0>() { cout << "I == " << 0 << '\n'; } int main(int argc, char *argv[]) { sa<1>(); return 0; } 

这表明gcc如何处理static_assert有一个严重的错误。

编辑 :哦,好吧。 我的程序有一个bug。 它应该读取I == 0 ,而不是I != 0 ,如果改变了,就不会像编译时那样编译。