请考虑以下代码,该代码无法访问undefinedFunction
。
void undefinedFunction();
template <bool b = false>
void foo()
{
static_assert(b == false);
if (b)
undefinedFunction();
}
int main()
{
foo();
}
GCC在没有投诉的情况下编译和链接。使用static_assert
,很难看出编译器如何做任何不同的事情,但标准对此有什么要说的吗?如果static_assert
被删除怎么办?编译器是否有义务删除分支,或者它实际上是否会发出一条无法访问的调用指令,这会导致链接器抱怨?
答案 0 :(得分:7)
通常,调用函数odr-使用它,有两个例外:如果它是纯虚拟的,或者它是否可能被评估([basic.def.odr] / 5)。除非表达式是未评估的操作数或其子表达式([basic.def.odr] / 2),否则可能会评估表达式。未评估的操作数出现在typeid
,sizeof
,noexcept
和decltype
中,这些都不适用于此处。因此,只要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中分析死代码。