在类定义中定义静态常量整数成员

我的理解是,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。

119298 次浏览

不仅仅是 int。但是你不能在类声明中定义值。如果你有:

class classname
{
public:
static int const N;
}

in the .h file then you must have:

int const classname::N = 10;

in the .cpp file.

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

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

知道是怎么回事吗?

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.

下面是章节:

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

看看朱棣文对一个可能的解决办法的回答。

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

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

比雅尼·斯特劳斯特鲁普的例子 abc0表明你是正确的,只需要一个定义,如果你采取的地址。

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 函数在后台以某种方式调用地址。

C + + 允许在类中定义静态 const 成员

不,3.12说:

声明是一个定义,除非 它声明一个函数而没有指定函数的主体(8.4) ,它包含外部说明符(7.1.1)或链接说明符(7.5) ,既不是初始化器也不是函数体 它在类定义中声明一个静态数据成员(9.4) ,它是一个类名声明(9.1) ,它是一个不透明枚举声明(7.2) ,或者它是一个 typedef 声明(7.1.3) ,一个 using 声明(7.3.3) ,或者一个 using 指令(7.3.4)。

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

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

(我认为疯狂埃迪的回答正确地描述了问题存在的原因。)

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

static constexpr int N = 10;

这在理论上仍然需要在。Cpp 文件,但是只要不采用 N的地址,任何编译器实现都不太可能产生错误;)。