在C ++中的类声明中初始化const成员


80

在PHP和C#中,可以在声明常量时对其进行初始化:

class Calendar3
{
    const int value1 = 12;
    const double value2 = 0.001;
}

我有一个函子的以下C ++声明,该声明与另一个类一起用于比较两个数学向量:

struct equal_vec
{
    bool operator() (const Vector3D& a, const Vector3D& b) const
    {
        Vector3D dist = b - a;
        return ( dist.length2() <= tolerance );
    }

    static const float tolerance = 0.001;
};

这段代码在使用g ++编译时没有问题。现在,在C ++ 0x模式下(-std = c ++ 0x),g ++编译器将输出一条错误消息:

错误:非整数类型的静态数据成员“公差”的类内初始化需要“ constexpr”

我知道我可以static const在类定义之外定义和初始化此成员。同样,可以在构造函数的初始化程序列表中初始化非静态常量数据成员。

但是,有什么方法可以像在PHP或C#中那样在类声明中初始化常量吗?

更新资料

static之所以使用关键字,是因为可以在g ++的类声明中初始化此类常量。我只需要一种在类声明中初始化常量的方法,无论它是否声明为常量static


5
I used static keyword just because it was possible to initialize such constants within the class declaration in g++. I just need a way to initialize a constant in a class declaration no matter if it declared as static or not.这是决定成员是否应该的错误方法static。永远不要让词汇惰性决定代码的语义。
Lightness Races in Orbit

That's the wrong way to decide whether a member should be static or not.我不同意 我认为这对于常任理事国并不重要。
ezpresso 2012年

3
@expresso:一点也不。您可以static使用实例特定的信息来初始化非常量成员。确定常量是类型的属性而不是特定实例的原因,是因为要使用它static,而不是因为您喜欢键入快捷键。
Lightness Races in Orbit

@lightless:可以,但是我看不出有任何理由使用具有不同值的相同于实例的常量进行初始化。我曾经为此使用非常量类字段!
ezpresso 2012年

4
为什么,如果它们在对象实例化之后再也没有改变过?struct myType { const std::time_t instantiated; myType() : instantiated(std::time(0)) {} };一切,可以const 应该const; 适用于staticstatic会员。
Lightness Races in Orbit

Answers:


136

在C ++ 11中,可以在类声明中初始化非static数据成员,static constexpr数据成员以及static const整数或枚举类型的数据成员。例如

struct X {
    int i=5;
    const float f=3.12f;
    static const int j=42;
    static constexpr float g=9.5f;
};

在这种情况下,i类的所有实例的成员X初始化为5由编译器生成的构造,并且f部件被初始化为3.12。的static const数据成员j初始化为42,将static constexpr数据成员g初始化为9.5

由于floatdouble不是整数或枚举类型,因此为了允许类定义中的初始值设定项,此类成员必须为constexpr或为非static

在C ++ 11之前,只有static const整数或枚举类型的数据成员才能在类定义中具有初始化程序。


是否有链接指向标准的标准部分?我刚刚开始使用它(尽管编译为C ++ 14),但它很有效,因为我愿意让编译器为我节省很多时间。但是,在阅读您的答案之前,我不确定它是否应该起作用!官方的话会帮助我增强信心,哈哈。首先,我也与类似的成员一起工作char const n[3]{'a', 'b', 'c'};
underscore_d

我不知道为什么static const int,但static constexpr float?这是什么意思float and double are not of integral or enumeration type
mrgloom

@mrgloom:是的,float和double不是。如果数据类型可以转换为整数,则它是整数类型。
ppadhy

45

初始化除const int类型以外的静态成员变量不是标准的C ++之前的C ++ 11。除非您指定该-pedantic选项,否则gcc编译器不会对此发出警告(并且仍然会生成有用的代码)。然后,您应该得到类似以下的错误:

const.cpp:3:36: error: floating-point literal cannot appear in a constant-expression
const.cpp:3:36: warning: ISO C++ forbids initialization of member constant ‘tolerance’ of non-integral type ‘const float’ [-pedantic]

这样做的原因是,C ++标准未指定应如何实现浮点并将其留给处理器。为了解决这个问题constexpr,引入了其他限制。



1

如果仅在一种方法中需要它,则可以将其局部声明为静态:

struct equal_vec
{
    bool operator() (const Vector3D& a, const Vector3D& b) const
    {
        static const float tolerance = 0.001f;
        Vector3D dist = b - a;
        return ( dist.length2() <= tolerance );
    }
};

1

我遇到了真正的问题,因为我需要相同的代码来使用不同版本的g ++(GNU C ++编译器)进行编译。因此,我必须使用宏来查看正在使用哪个版本的编译器,然后采取相应的措施,如下所示

#if __GNUC__ > 5
 #define GNU_CONST_STATIC_FLOAT_DECLARATION constexpr
#else
 #define GNU_CONST_STATIC_FLOAT_DECLARATION const
#endif

GNU_CONST_STATIC_FLOAT_DECLARATION static double yugeNum=5.0;

对于g ++ 6.0.0之前的版本,它将对所有内容使用'const',然后对于6.0.0及更高版本的g ++使用'constexpr'。这是对发生更改的版本的猜测,因为坦率地说,直到g ++ 6.2.1版我才注意到这一点。要正确执行此操作,您可能必须查看g ++的次要版本和补丁号,因此请参阅

https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html

有关可用宏的详细信息。

使用gnu,您还可以坚持在各处使用'const',然后使用该-fpermissive标志进行编译,但这会发出警告,我希望我的东西可以干净地编译。

不太好,因为它特定于gnu编译器,但是我怀疑您可以对其他编译器执行类似操作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.