38

我已经在 C++17 编译器 (Coliru) 中编译并运行了以下程序。在程序中,我声明了一个extern变量,但没有定义它。但是,编译器不会给出链接器错误

#include <iostream>

extern int i; // Only declaration

int func() 
{
    if constexpr (true)
        return 0;
    else if (i)
        return i;
    else
        return -1;
}

int main() 
{
    int ret = func();
    std::cout<<"Ret : "<<ret<<std::endl;
}

为什么编译器不给出链接器错误?

4

4 回答 4

58

因为该变量未使用 odr。你有一个constexpr if总是丢弃可以使用它的分支。

要点之一constexpr if是丢弃的分支甚至不需要编译,只需格式良好。这就是我们如何在废弃分支中调用不存在的成员函数。

于 2017-07-11T07:24:48.747 回答
41

在您的情况下,该变量仅用于丢弃的语句。然而,即使我们忽略了这一事实,C++ 语言规范仍然明确指出,对于缺失的定义不需要诊断

3.2 一定义规则

4每个程序都应包含一个定义,该定义在被丢弃的语句(6.4.1)之外在该程序中使用的每个非内联函数或变量;无需诊断

语言规范理解优化编译器可能足够聪明,可以消除变量的所有 odr 使用。在这种情况下,要求实施检测和报告潜在的 ODR 违规行为将是过度且不必要的。

于 2017-07-11T07:32:03.907 回答
9

因为编译器会产生编译器错误,所以链接器会产生链接器错误......

不,说真的:

if constexpr (true)

总是正确的,所以编译器会忽略 if 子句的其余部分,因为它永远不会到达。所以i实际上从未使用过。

于 2017-07-11T07:25:47.873 回答
1

这已经得到了回答,但如果你有兴趣,cppreference.com正好有这个例子constexpr if

Consexpr If

以 开头的语句if constexpr称为constexpr if 语句

在 constexpr if 语句中,条件的值必须是上下文转换的 bool 类型的常量表达式。如果值为 true,则丢弃statement-false(如果存在),否则丢弃statement-true
[...]
被丢弃的语句可以使用未定义的变量:

extern int x; // no definition of x required
int f() {
if constexpr (true)
    return 0;
else if (x)
    return x;
else
    return -x;
}
于 2017-08-25T07:47:08.167 回答