对静态常量积分类型的未定义引用

Undefined reference to static const integral type

本文关键字:未定义 引用 类型 静态 常量      更新时间:2023-10-16

我对静态整数常量有一个奇怪的行为:

#include <iostream>
#include <inttypes.h>
class Test{
public:
static const uint32_t Magic = 0x1123;
};
class DataStream{
public:
template<typename T>
DataStream& operator <<( const T& value )
{
std::cout << value << std::endl;
return *this;
}
};
int main()
{
DataStream s;
uint32_t a = Test::Magic;  // ok
bool compare = ( a == Test::Magic ); // ok
s << compare;
s << a;
s << Test::Magic;  // fail
return 0;
}

我知道这样的常量应该在类外定义.cpp

const uint32_t Test::Magic;

但奇怪的是,上面的代码在外行s << Test::Magic;下工作正常,并且只有在直接与模板operator <<一起使用时才Magic产生错误。

GCC出现更多的错误undefined reference to 'Test::Magic',但MSVC不会出现。

问题是为什么我应该在类外定义Test::Magic(即使没有值!!(,以及为什么我的代码在某些情况下即使没有这样的定义也能正常工作?

通常,如果使用 ODR,则应.cpp文件中定义所有静态常量名称。参考论点是ODR using他们。但是,违反此规则是未定义的行为,MSVC 不报告错误只是显示未定义行为的方式之一。

作为实际考虑因素,当函数未内联时,您可能会遇到错误,并且对于内联函数可能看不到错误。我的猜测是,内联的工作方式与您用于这些编译器的优化级别不同。

§ 9.4.2 静态数据成员 [class.static.data]

  1. 如果非易失性 const 静态数据成员是整型或枚举类型,则其在类定义中的声明可以指定 大括号或等于初始值设定项 [...]这如果成员在程序中是 ODR-use(3.2(,则仍应在命名空间作用域中定义成员,并且命名空间作用域定义不应 包含初始值设定项。

  2. [ 注意:程序中应只有一个odr 使用的静态数据成员定义 (3.2(;无需诊断。—尾注 ]