Jeka
Jeka

Reputation: 1384

Undefined reference to static const integral type

I have a weird behaviour with static integal constants:

#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;
}

I know that such constants should be defined outside of class in .cpp as

const uint32_t Test::Magic;

But strange things is that code above work fine with out line s << Test::Magic; and produce error only if Magic used with template operator << directly.

Even more error undefined reference to 'Test::Magic' appear with GCC, but not with MSVC.

The question is why I should define Test::Magic outside of class (even without value!!!), and why my code work fine in some conditions even without such definition?

Upvotes: 4

Views: 1288

Answers (2)

bolov
bolov

Reputation: 75853

§ 9.4.2 Static data members [class.static.data]

  1. If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer [...] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.

  2. [ Note: There shall be exactly one definition of a static data member that is odr-used (3.2) in a program; no diagnostic is required. —end note ]

Upvotes: 1

SergeyA
SergeyA

Reputation: 62603

As a rule, all static const names should be defined in .cpp file if they are ODR used. Taking a reference to the argument is ODR using them. However, having violated this rule is undefined behavior, and MSVC not reporting an error is just one of the ways undefined behavior can be manifested.

As a practical consideration, you are likely to have the error when function is not inlined, and probably won't see it for the inlined functions. My guess is that inlining works differently with the level of optimization you are using for those compilers.

Upvotes: 2

Related Questions