需要定义
您提供的代码是非标准的。虽然您可以直接在类中为 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 and static specifiers 的类似问题中找到来自标准的引用
为什么有时代码在没有定义的情况下“工作”?
至于为什么即使不提供定义也经常可以绕过:如果您仅在常量表达式中使用这些成员,编译器将始终直接解析它们,并且链接器解析将没有访问权限。只有当您以某种方式使用它时编译器无法直接处理,并且只有在这种情况下,链接器才会检测到符号未定义。我猜这可能是 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也会出错,并且不需要像标准那样严格的定义:
当(且仅当)它具有类外定义时,您可以获取静态成员的地址
9.4.2中的标准要求该定义:
C++03 措辞:
如果在程序中使用该成员,则该成员仍应在名称空间范围内定义,并且名称空间范围定义不应包含初始值设定项
9.4.2 的 C++11 措辞有点不同:
3如果该成员在程序中被 odr-used (3.2),则该成员仍应在命名空间范围内定义
3.2 说以下关于 odr-use 的内容:
3变量 x 其名称显示为潜在求值表达式 ex 是 odr-used 除非 x 是满足出现在常量表达式 (5.19) 中的要求并且 ex 是表达式的潜在结果集的元素e,其中左值到右值的转换(4.1)应用于 e,或者 e 是丢弃值表达式(第 5 条)。
4每个程序都应包含该程序中使用的每个非内联函数或变量的准确定义;无需诊断。
我不得不承认我不确定 C++11 措辞的确切含义是什么,因为我无法理解 odr-use 规则。