静态无法访问的调用是否会导致未定义的引用错误?

时间:2016-04-08 22:03:02

标签: c++ c++11 c++14 template-meta-programming

请考虑以下代码,该代码无法访问undefinedFunction

void undefinedFunction();

template <bool b = false>
void foo()
{
  static_assert(b == false);
  if (b)
    undefinedFunction();
}

int main()
{
  foo();
}

GCC在没有投诉的情况下编译和链接。使用static_assert,很难看出编译器如何做任何不同的事情,但标准对此有什么要说的吗?如果static_assert被删除怎么办?编译器是否有义务删除分支,或者它实际上是否会发出一条无法访问的调用指令,这会导致链接器抱怨?

3 个答案:

答案 0 :(得分:7)

通常,调用函数odr-使用它,有两个例外:如果它是纯虚拟的,或者它是否可能被评估([basic.def.odr] / 5)。除非表达式是未评估的操作数或其子表达式([basic.def.odr] / 2),否则可能会评估表达式。未评估的操作数出现在typeidsizeofnoexceptdecltype中,这些都不适用于此处。因此,只要undefinedFunction被实例化,foo就会被使用。对于#34;静态无法访问&#34;没有例外。代码。

答案 1 :(得分:4)

根据C ++标准§3.2/ p4单定义规则[basic.def.odr](强调我的)

  

每个程序都应包含每个非内联的一个定义   在该程序中使用的函数或变量;没有诊断   需要。定义可以在程序中明确显示,也可以   可以在标准库或用户定义的库中找到,或者(在   适当的)它是隐式定义的(见12.1,12.4和12.8)。一个   内联函数应在其中的每个翻译单元中定义   是有用的。

模板函数foo被实例化undefinedFunction使用了odr(即,需要undefinedFunction的定义)。如果不评估if子句,则无关紧要。因此,该程序形成不良,并且由于不需要诊断,因此可以链接或不连接。

答案 2 :(得分:1)

正如其他人评论的那样,两个单独的步骤对此有所贡献。优化程序可能会删除无法访问的代码,因此永远不会请求undefinedFunction()的链接。 编译步骤不关心symbols that are not defined(有关this community answer中编译的更多信息)。

这与static_assert无关。你可以在模板代码中使用永远不会被初始化的未定义引用,并且编译成功,因为编译器从不考虑代码,它永远不会发出对链接的要求。

如果符号通过,并在稍后的步骤中请求,则链接将失败。这与使用模板类编译库时发生的情况相同,后来尝试使用带有未明确初始化类的参数类型的模板,您将使用编译好的库获得对类型的未定义引用&# 39;拥有。

如果您希望检查编译器是否实际消除了死代码,this answer详细说明了如何在GCC中分析死代码。