即使模板函数无处调用,static_assert也无法编译

Ste*_*and 33 c++ templates g++ static-assert c++11

我使用g ++ 4.6.3(目前是ubuntu 12.04的默认包),标志为c ++ 0x,我偶然发现:

template <typename T>
inline T getValue(AnObject&)
{
    static_assert(false , "this function has to be implemented for desired type");
}
Run Code Online (Sandbox Code Playgroud)

编译错误:

static_assertion failed "this function has to be implemented for the desired type"
Run Code Online (Sandbox Code Playgroud)

即使我还没有在任何地方调用此功能.

这是一个g ++错误吗?只有在代码中的某处调用此函数时,才应该实现此函数.

Jon*_*ely 50

标准在[temp.res]/8中说

不能为可以生成有效特化的模板定义发出诊断.如果无法为模板定义生成有效的专业化,并且未实例化该模板,则模板定义格式错误,无需诊断.... [注意:如果实例化模板,将根据本标准中的其他规则诊断错误.确切地说,这些错误被诊断出来是一个实施质量问题. - 结束说明]

没有可能的方法来实例化将要编译的函数模板,因此模板定义格式错误,因此即使未实例化,编译器也允许(但不是必需)拒绝它.

你可以让它像这样工作:

template<typename T>
struct foobar : std::false_type
{ };

template <typename T>
inline T getValue(AnObject&)
{
    static_assert( foobar<T>::value , "this function has to be implemented for desired type");
}
Run Code Online (Sandbox Code Playgroud)

现在,编译器不能立即拒绝该函数模板,因为直到它被实例化,它不知道是否会有一个专门的foobarvalue == true.实例化时,foobar<T>将实例化相关的特化,并且静态断言仍将失败,如期望的那样.

  • C++17 替代方案:`template &lt;typename...&gt; inline constexpr bool always_false = false; static_assert(always_false&lt;T&gt;, "随便");`。 (4认同)
  • 这个答案太棒了.我无法相信人们发明的所有方式使C++屈服于他们的意志.语言很广泛. (3认同)

And*_*owl 26

那是因为条件不依赖于模板参数.因此,编译器甚至可以在实例化该模板之前对其进行评估,并在评估产生时生成相关的编译错误消息false.

换句话说,这不是一个错误.虽然只有在实例化模板后才能检查很多东西,但是编译器甚至可以执行其他有效性检查.这就是为什么C++具有两阶段名称查找的原因.编译器只是试图帮助您找到100%可能发生的错误.

  • @StephaneRolland:然后使用`static_assert()`,但在某些模板参数上使条件*依赖*.使它总是会为你要用它实例化的参数产生`false`(例如`static_assert(typename is_same <T,type_false> :: value),"Error!")`,但是请提一下模板条件中的论据.这将告诉编译器:"嘿,这是一个依赖名称,所以等到实例化之前判断..." (5认同)
  • @StephaneRolland:注意`static_assert(sizeof(T)== 0,"错误!")`通常被提出作为另一个解决方案,但我认为*这个共识是,这也可能"早"失败,因为编译器可以知道大小永远不会小于1甚至没有看到`T`.只是为了保持这一点. (2认同)

Che*_*Alf 5

这确实是一个注释,但需要一个代码示例。

神圣标准的措辞static_assert不限制其对实例化代码的影响。

然而,代码

template <typename T>
inline T getValue(int&)
{
    typedef char blah[-1];  // Common C++03 static assert, no special semantics.
}

int main()
{}
Run Code Online (Sandbox Code Playgroud)

也无法使用 MinGW g++ 4.7.2 进行编译,这突出了这个问题。

认为答案是 g++ 是正确的,而不会为此产生编译错误的 Visual C++ 11.0 是错误的,但我很难根据神圣标准的经文提供相关分析。

编译器差异的一个实际后果是,目前您不能依赖该行为。