当我尝试编译时,
#include <iostream>
struct K{
const static int a = 5;
};
int main(){
K k;
std::cout << std::min(k.a, 7);
}
我得到了关注。 gcc
和clang
都会出现类似错误:
/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
也可以正常工作。
答案 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的回答。