在类定义中定义静态const整数成员

时间:2010-06-11 20:26:49

标签: c++ static declaration definition

我的理解是C ++允许在类中定义静态const成员,只要它是整数类型。

为什么以下代码会给我一个链接器错误?

#include <algorithm>
#include <iostream>

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

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

我得到的错误是:

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

有趣的是,如果我注释掉对std :: min的调用,代码编译和链接就好了(即使test :: N也在前一行引用)。

知道发生了什么事吗?

我的编译器是Linux上的gcc 4.4。

7 个答案:

答案 0 :(得分:64)

我的理解是C ++允许在类中定义静态const成员,只要它是整数类型。

你是对的。您可以在类声明中初始化静态const积分,但这不是定义。

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

有趣的是,如果我注释掉对std :: min的调用,代码编译并链接就好了(即使test :: N也在前一行引用)。

知道发生了什么事吗?

std :: min通过const引用获取其参数。如果它按值获取它们你就没有这个问题,但由于你需要一个引用,你还需要一个定义。

这是章节/经文:

9.4.2 / 4 - 如果static数据成员是const整数或const枚举类型,则其在类定义中的声明可以指定a 常量初始化器,它应是一个整数常量表达式(5.19)。在这种情况下,成员可以出现在整数常量表达式中。如果在程序中使用该成员,并且命名空间作用域定义不包含初始化程序,则该成员仍应在名称空间作用域中定义。

请参阅Chu的答案,了解可能的解决方法。

答案 1 :(得分:44)

Bjarne Stroustrup的例子in his C++ FAQ表明你是对的,如果你拿地址,只需要一个定义。

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
    // ...
}

他说“如果(并且只有)它有一个类外定义”,你可以获取一个静态成员的地址。这表明它会起作用。也许你的min函数会在幕后以某种方式调用地址。

答案 2 :(得分:23)

另外,对于整数类型,另一种方法是将常量定义为类中的枚举:

class test
{
public:
    enum { N = 10 };
};

答案 3 :(得分:10)

不仅仅是int。但是您无法在类声明中定义该值。如果你有:

class classname
{
    public:
       static int const N;
}
<。>在.h文件中,你必须有:

int const classname::N = 10;
<。>在.cpp文件中。

答案 4 :(得分:9)

这是解决问题的另一种方法:

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

(我认为Crazy Eddie的答案正确地描述了问题存在的原因。)

答案 5 :(得分:4)

从C ++ 11开始,您可以使用:

static constexpr int N = 10;

理论上,这仍然需要您在.cpp文件中定义常量,但只要您不使用N的地址,任何编译器实现都不太可能产生错误;)。

答案 6 :(得分:3)

  

C ++允许在类

中定义静态const成员

不,3.1§2说:

  

声明是一个定义,除非声明一个函数而没有指定函数的主体(8.4),它包含extern说明符(7.1.1)或链接规范(7.5)并且都不是初始化器也不是函数体,它在类定义中声明了一个静态数据成员(9.4),它是一个类名声明(9.1),它是一个opaque-enum-declaration(7.2),或者它是typedef声明(7.1.3),using声明(7.3.3)或using-directive(7.3.4)。