views:

164

answers:

5

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.

+5  A: 

Not just int's. But you can't define the value in the class declaration. If you have:

class classname
{
    public:
       static int const N;
}

in the .h file then you must have:

int const classname::N = 10;

in the .cpp file.

Amardeep
I am aware that you can *declare* a variable of any type inside the class declaration. I said that I thought static integer constants could also be *defined* inside the class declaration. Is this not the case? If not, why is it that the compiler does not give an error at the line where I try to define it inside the class? Moreover, why does the std::cout line not cause a linker error, but the std::min line does?
HighCommander4
No, can't define static members in the class declaration because the initialization emits code. Unlike an inline function which also emits code, a static definition is globally unique.
Amardeep
@HighCommander4: You can supply an initializer for the `static const` integral member in the class definition. But that still *does not define* that member. See Noah Roberts answer for details.
AndreyT
+6  A: 
Noah Roberts
I see, that's interesting. In that case, what is the difference between providing the value at the point of declaration versus providing the value at the point of definition? Which one is recommended?
HighCommander4
Well, I believe that you can get away without a definition so long as you never actually "use" the variable. If you only use it as a part of a constant expression then the variable is never used. Otherwise there doesn't seem to be a huge difference besides being able to see the value in the header - which may or may not be what you want.
Noah Roberts
+3  A: 

Another way to do this, for integer types anyway, is to define constants as enums in the class:

class test
{
public:
    enum { N = 10 };
};
Stephen Chu
And this would probably solve the problem. When N is used as a parameter for min() it will cause a temporary to be created rather than try to refer to a supposedly existing variable.
Noah Roberts
+2  A: 

Bjarne Stroustrup's example in his C++ FAQ suggests you are correct, and only need a definition if you take the address.

class AE {
    // ...
public:
    static const int c6 = 7;
    static const int c7 = 31;
};

const int AE::c7;   // definition

int f()
{
    const int* p1 = &AE::c6;    // error: c6 not an lvalue
    const int* p2 = &AE::c7;    // ok
    // ...
}

He says "You can take the address of a static member if (and only if) it has an out-of-class definition". Which suggests it would work otherwise. Maybe your min function invokes addresses somehow behind the scenes.

Hostile Fork
A: 

C++ allows static const members to be defined inside a class

Nope, 3.1 §2 says:

A declaration is a definition unless it declares a function without specifying the function's body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification (7.5) and neither an initializer nor a functionbody, it declares a static data member in a class definition (9.4), it is a class name declaration (9.1), it is an opaque-enum-declaration (7.2), or it is a typedef declaration (7.1.3), a using-declaration (7.3.3), or a using-directive (7.3.4).

FredOverflow