c++staticdeclarationdefinition

Defining static const integer members in class definition


My understanding is that C++ allows static const members to be defined inside a class so long as it's an integer type.

Why, then, does the following code give me a linker error?

#include <algorithm>
#include <iostream>

class test
{
public:
    static const int N = 10;
};

int main()
{
    std::cout << test::N << "\n";
    std::min(9, test::N);
}

The error I get is:

test.cpp:(.text+0x130): undefined reference to `test::N'
collect2: ld returned 1 exit status

Interestingly, if I comment out the call to std::min, the code compiles and links just fine (even though test::N is also referenced on the previous line).

Any idea as to what's going on?

My compiler is gcc 4.4 on Linux.


Solution

  • For over a decade now C++ provides the constexpr keyword that handles this nonsense and much more. Declare your value as static constexpr and it won't need a definition. The rest of this answer still applies to people consigned to hell permanently.


    My understanding is that C++ allows static const members to be defined inside a class so long as it's an integer type.

    You are sort of correct. You are allowed to initialize static const integrals in the class declaration but that is not a definition.

    Interestingly, if I comment out the call to std::min, the code compiles and links just fine (even though test::N is also referenced on the previous line).

    Any idea as to what's going on?

    std::min takes its parameters by const reference. If it took them by value you'd not have this problem but since you need a reference you also need a definition.

    Here's chapter/verse:

    9.4.2/4 - If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.

    See Chu's answer for a possible workaround.