需要定义
您提供的代码是非标准的。虽然您可以在类中直接为const static int成员提供初始值,但仍需要提供单独的定义。这很奇怪,有点出人意料,但您需要像这样编写:
#include <algorithm>
struct Foo
{
static const int A = 1;
static const int B = 2;
};
const int Foo::A;
const int Foo::B;
int main()
{
return std::min(Foo::A, Foo::B);
}
可以在类似于C++中的const和static修饰符的问题中找到标准的引用。
为什么有时候代码在没有定义的情况下“能够工作”?
至于为什么即使不提供定义也经常可以解决问题:如果您仅在常量表达式中使用这些成员,编译器将始终直接解析它们,并且不会留下链接器分辨率的访问。只有当您以某种无法由编译器直接处理的方式使用它时,链接器才会检测到符号未定义。我想这可能是Visual Studio编译器中的一个错误,但考虑到该错误的性质,我怀疑它永远不会被修复。
我不明白为什么您的源代码属于“链接器”类别,需要剖析std::min才能理解。 注意:当我在GCC在线测试时,它可以正常工作,错误没有被检测到。
另一种选择:使用枚举
另一个选择是使用枚举。 当您遇到不支持静态const int“内联”初始化程序的旧编译器(例如Visual Studio 6)时,此版本也很方便。 但请注意,对于std::min,使用枚举会遇到其他问题,并且需要使用显式实例化或转换,或者在一个命名的枚举中同时包含A和B,如Nawaz的答案所示:
struct Foo
{
enum {A = 1};
enum {B = 2};
};
int main()
{
return std::min<int>(Foo::A, Foo::B);
}
标准
注意:即使Stroustrup C++ FAQ也犯了这个错误,并不像标准那样严格要求定义:
如果静态成员有一个类外定义,你才能取它的地址。
C++标准确实在9.4.2中要求必须提供定义:
C++03措辞:
如果程序中使用该成员并且命名空间作用域定义不包含初始化器,则该成员仍然应在名称空间范围内定义。
C++11对9.4.2的措辞略有不同:
3 如果该成员在程序中odr-used(3.2),则仍应在名称空间范围内定义。
3.2描述了odr-use:
3 变量x在表达式ex中作为可能评估的表达式出现的情况下是odr-used,除非x是满足出现在常量表达式(5.19)中的要求的对象,而ex是表达式e的潜在结果集中的元素,在其中对e应用左值到右值转换(4.1),或者e是一个废弃值表达式(第5条)。
4 每个程序必须包含在该程序中使用odr的每个非内联函数或变量的精确定义;不需要诊断。
我必须承认,我不确定C++11措辞的确切含义,因为我未能理解odr-use规则。