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

在类定义中定义静态常量整数成员 我的理解是C++允许静态const成员在类中定义,只要它是整数类型。,c++,static,declaration,definition,C++,Static,Declaration,Definition,那么,为什么下面的代码会给我一个链接器错误 #include <algorithm> #include <iostream> class test { public: static const int N = 10; }; int main() { std::cout << test::N << "\n"; std::min(9, test::N); } 有趣的是,如果我注释掉对std::min的调用,代码编译和链接都

那么,为什么下面的代码会给我一个链接器错误

#include <algorithm>
#include <iostream>

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

int main()
{
    std::cout << test::N << "\n";
    std::min(9, test::N);
}
有趣的是,如果我注释掉对std::min的调用,代码编译和链接都很好(尽管前一行也引用了test::N)

知道发生了什么事吗


我的编译器是Linux上的GCC4.4。

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

class classname
{
    public:
       static int const N;
}
在.h文件中,您必须具有:

int const classname::N = 10;
<> P>我的理解是C++允许静态const成员在类中定义,只要是整数类型。< /P> 你说得有点对。允许在类声明中初始化静态常量积分,但这不是定义

有趣的是,如果我注释掉对std::min的调用,代码编译和链接都很好(尽管前一行也引用了test::N)

知道发生了什么事吗

std::min通过常量引用获取其参数。如果它按值取它们,你就不会有这个问题,但是因为你需要一个引用,你也需要一个定义

以下是章节:

9.4.2/4-如果
静态
数据成员为
常量
整数或
常量
枚举类型,则其在类定义中的声明可以指定常量初始值设定项,该初始值设定项应为整数常量表达式(5.19)。在这种情况下,成员可以出现在积分常量表达式中。如果在程序中使用该成员,则该成员仍应在名称空间范围中定义,且名称空间范围定义不应包含初始值设定项


有关可能的解决方法,请参见Chu的答案。

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

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

Bjarne Stroustrup的例子表明您是正确的,并且只有在您使用地址时才需要定义

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++允许在类中定义静态常量成员

不,第3.1条第2款规定:

声明是一个定义,除非它声明一个函数而不指定函数体(8.4),它包含外部说明符(7.1.1)或链接规范(7.5),既不包含初始值设定项也不包含函数体,它声明类定义中的静态数据成员(9.4),它是类名声明(9.1)、不透明枚举声明(7.2)或typedef声明(7.1.3)、使用声明(7.3.3)或使用指令(7.3.4)


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

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

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

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

static constexpr int N=10


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

我知道您可以在类声明中声明任何类型的变量。我说过,我认为静态整数常量也可以在类声明中定义。不是这样吗?如果不是,为什么编译器在我试图在类中定义它的那一行没有给出错误?此外,为什么std::cout行不会导致链接器错误,而std::min行会导致错误?不,不能在类声明中定义静态成员,因为初始化会发出代码。与同时发出代码的内联函数不同,静态定义是全局唯一的。@HighCommander4:您可以为类定义中的
静态常量
整数成员提供初始值设定项。但这仍然没有定义该成员。有关详细信息,请参见Noah Roberts答案。在Visual Studio 2010上工作正常。在中解释了此确切错误,在
char
的特定情况下,您可以将其定义为
constepr static const char&N=“N”[0]。注意
。我想这是因为文字字符串是自动定义的。我有点担心,因为它可能在不同的翻译单元中的头文件中表现得很奇怪,因为字符串可能位于多个不同的地址。这个问题是一个明显的例子:C++对“不使用常量定义常数”的回答仍然是“JohannesOvermann”。我想提一下对全局变量使用内联,因为C++17
inline const int N=10
,据我所知,它仍然有一个由链接器定义的存储空间。在本例中,关键字inline还可以用于在类定义测试中提供静态变量定义。在这种情况下,在声明点提供值与在定义点提供值之间有什么区别?推荐哪一种?好吧,我相信你可以不用定义,只要你从来没有真正“使用”过变量。如果仅将其用作常量表达式的一部分,则永远不会使用该变量。否则,除了能够看到标题中的值之外,似乎没有太大的区别——这可能是您想要的,也可能不是您想要的;是右值,但不是左值。该值在编译时(您可以使用它对数组进行尺寸标注)静态常量时作为常量提供;[no initializer]必须在cpp文件中定义,并且可以用作右值或左值。如果他们能够扩展/改进此功能,那就太好了。在我看来,初始化但未定义的对象应该与lite一样对待
std::min(9, int(test::N));