Defining static const integer members in class def

2019-01-01 15:17发布

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.

7条回答
看淡一切
2楼-- · 2019-01-01 15:36

Here's another way to work around the problem:

std::min(9, int(test::N));

(I think Crazy Eddie's answer correctly describes why the problem exists.)

查看更多
何处买醉
3楼-- · 2019-01-01 15:36

As of C++11 you can (and you want) to use:

static constexpr int N = 10;

that does not require you to define the constant in a .cpp file.

查看更多
怪性笑人.
4楼-- · 2019-01-01 15:39

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.

查看更多
孤独寂梦人
5楼-- · 2019-01-01 15:43

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.

http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr038.htm

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.

查看更多
泪湿衣
6楼-- · 2019-01-01 15:46

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

class test
{
public:
    enum { N = 10 };
};
查看更多
孤独寂梦人
7楼-- · 2019-01-01 15:55

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).

查看更多
登录 后发表回答