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

时间:2017-08-16 17:10:55

标签: c++

我对静态积分常数有一种奇怪的行为:

#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;,并且仅当Magic直接与模板operator <<一起使用时才会产生错误。

更多错误undefined reference to 'Test::Magic'GCC一起显示,但与MSVC不一致。

问题是为什么我应该在课外定义Test::Magic(即使没有价值!!!),为什么我的代码在某些条件下工作正常,即使没有这样的定义?

2 个答案:

答案 0 :(得分:2)

通常,如果它们是ODR used,则应在.cpp文件中定义所有静态const名称。参考这个论点是ODR using他们。但是,违反此规则是未定义的行为,并且MSVC不报告错误只是未定义行为可以表现的方式之一。

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

答案 1 :(得分:1)

  

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

     
      
  1. 如果非易失性const静态数据成员是整数或枚举类型,则其在类定义中的声明可以指定   支撑或平等初始化器[...]   如果成员使用,则仍应在命名空间范围内定义   (3.2)在程序和命名空间范围定义中不得   包含初始化程序。

  2.   
  3. [注意:程序中有一个静态数据成员的确切的一个定义是odr-used(3.2); 无需诊断。    - 尾注]

  4.