奇怪的C ++链接错误

时间:2016-03-22 12:35:23

标签: c++ gcc clang min

当我尝试编译时,

#include <iostream>

struct K{
    const static int a = 5;
};

int main(){
    K k;

    std::cout << std::min(k.a, 7);
}

我得到了关注。 gccclang都会出现类似错误:

/tmp/x-54e820.o: In function `main':
x.cc:(.text+0xa): undefined reference to `K::a'
clang-3.7: error: linker command failed with exit code 1 (use -v to see invocation)

如果我这样做,它编译没有问题。这与std::min的撰写方式有关吗?

#include <iostream>

struct K{
    const static int a = 5;
};

int main(){
    K k;

    std::cout << std::min((int) k.a, 7);  // <= here is the change!!!
}

另一种避免错误的方法是,如果我自己做min()

template <class T>
T min(T const a, T const b){
    return a < b ? a : b;
}

类似C的预处理器MIN也可以正常工作。

3 个答案:

答案 0 :(得分:8)

std::min通过引用接受参数。将引用绑定到对象意味着该对象是 odr-used ([basic.def.odr] / 2中的代码示例与您的示例几乎相同)。

但在(int)k.a案例中,k.a不是 odr-used ;因为它正在执行左值到右值的转换,从而产生一个常量表达式。 (这里还有一些其他条件,但你的代码还可以)。

如果某个对象是 odr-used ,那么它必须只有一个定义;违反此规则无需诊断。所以第一种情况可能会也可能不会被接受;第二种情况必须被接受。

在您自己的min版本中,它按值进行参数,类似于(int)k.a情况 - 对k.a采取的唯一操作是进行rvalue转换以初始化参数您的min

您可以在C ++标准草案的[basic.def.odr]部分阅读有关 odr-use 的完整规则。

答案 1 :(得分:2)

这个问题经常被问到。 我相信这是一个铿锵的错误。 a过早被检测为常量表达式,并且编译器没有生成它的定义。(请参阅注释中的更正)

std::min通过const引用获取其参数,因此必须存在定义。

#include <iostream>

struct K{
    const static int a = 5;
};

int main(){
    K k;

    std::cout << std::min(k.a, 7);
}

这是一个便携式解决方法替代方案:

#include <iostream>

struct K{
    constexpr static int a() { return 5; }
};


int main(){
    K k;

    std::cout << std::min(k.a(), 7);
}

答案 2 :(得分:-2)

您已在结构中声明了一个静态变量(a),但尚未对其进行定义。

struct K
{
    const static int a; // declaration
};

const int K::a = 5; // definition 


int main()
{
    std::cout << std::min(K::a, 7);
}

您可能会发现this link有帮助。

我也同意Richard Hodges的回答。