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

HC4*_*ica 105 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);
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

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

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

知道发生了什么事吗?

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

Edw*_*nge 70

我的理解是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枚举类型,它在类定义中的声明可以指定一个常量初始化器,它应该是一个整型常量表达式(5.19).在这种情况下,成员可以出现在整数常量表达式中.如果在程序中使用该成员,并且名称空间范围定义不包含初始化程序,则该成员仍应在名称空间作用域中定义.

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

  • 简洁的答案是 static const x=1; 是右值但不是左值。该值在编译时可用作常量(您可以用它来定义数组的维度) static const y; [no initializer] 必须在 cpp 文件中定义,并且可以用作右值或左值。 (2认同)
  • 如果他们可以扩展/改善这一点,那就太好了。我认为,初始化但未定义的对象应与文字相同。例如,我们可以将文字“ 5”绑定到“ const int&”。那么为什么不将OP的`test :: N`当作对应的文字呢? (2认同)

Hos*_*ork 48

Bjarne Stroustrup 在他的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
    // ...
}
Run Code Online (Sandbox Code Playgroud)

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

  • `std :: min`通过引用获取其参数,这就是需要定义的原因. (2认同)

Ste*_*Chu 23

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

class test
{
public:
    enum { N = 10 };
};
Run Code Online (Sandbox Code Playgroud)

  • 这可能会解决问题.当N用作min()的参数时,它将导致创建临时而不是尝试引用所谓的现有变量. (2认同)

Ama*_*9MF 11

不只是int's.但是您无法在类声明中定义该值.如果你有:

class classname
{
    public:
       static int const N;
}
Run Code Online (Sandbox Code Playgroud)

在.h文件中你必须有:

int const classname::N = 10;
Run Code Online (Sandbox Code Playgroud)

在.cpp文件中.

  • 我知道你可以在类声明中*声明*任何类型的变量.我说我认为静态整数常量也可以在类声明中定义*.这不是这种情况吗?如果没有,为什么编译器不会在我尝试在类中定义它的行中给出错误?此外,为什么std :: cout行不会导致链接器错误,但是std :: min行呢? (2认同)

kar*_*doc 9

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

std::min(9, int(test::N));
Run Code Online (Sandbox Code Playgroud)

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

  • 甚至`std :: min(9,+ test :: N);` (5认同)

Car*_*ood 5

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

static constexpr int N = 10;

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