C++11初始化类静态常量数组

8

我正在尝试的是使用MinGW g++ 4.7.0。

#include <iostream>
#include <string>

class Fruit
{
public:
    enum Value { APPLE, ORANGE, BANANA, NONE };
    static const Value VALUES[4] = { APPLE, ORANGE, BANANA, NONE };
    Fruit (Value v = NONE) : v_(v) { };
    std::string to_string () const {
        switch (v_) {
            case APPLE: return "apple";
            case ORANGE: return "orange";
            case BANANA: return "banana";
            default: return "none";
        }
    }
private:
    Value v_;
};

int main (int argc, char * argv[])
{
    for (Fruit f : Fruit::VALUES)
        std::cout << f.to_string() << std::endl;
    return 0;
}

我尝试编译它并得到以下输出:

>g++ -std=c++0x test.cpp
test.cpp:9:66: error: 'constexpr' needed for in-class initialization of static d
ata member 'const Fruit::Value Fruit::VALUES [4]' of non-integral type [-fpermis
sive]


>g++ -std=c++0x -fpermissive test.cpp
test.cpp:9:66: warning: 'constexpr' needed for in-class initialization of static
 data member 'const Fruit::Value Fruit::VALUES [4]' of non-integral type [-fperm
issive]
cc1l4Xgi.o:test.cpp:(.text+0x1a): undefined reference to `Fruit::VALUES'
collect2.exe: error: ld returned 1 exit status

C++11是否允许像这样在类中初始化静态const数组?还是必须像C++11之前一样在类外定义?
1个回答

17

test.cpp:9:66: 错误:'constexpr'在静态数据成员 'const Fruit::Value Fruit::VALUES [4]' 中的类内初始值设定中是必须的,因为其类型不是整数类型 [-fpermissive]

编译器告诉了需要什么:

class Fruit
{
public:
    enum Value { APPLE, ORANGE, BANANA, NONE };
    static constexpr Value VALUES[4] = { APPLE, ORANGE, BANANA, NONE };
    //     ^^^^^^^^^
...
};

cc1l4Xgi.o:test.cpp:(.text+0x1a): 对于 `Fruit::VALUES',存在未定义的引用

为了让链接器满意,您必须在源代码文件中(而不是头文件中)添加此行:

constexpr Fruit::Value Fruit::VALUES[4];

编辑: 自 C++17 起,我们拥有内联变量,每个 constexpr 变量都是内联的,因此在 C++17 中问题得到了解决。


嘿,我有同样的问题,但我想知道为什么链接器需要这行代码?C++11不已经支持在类定义中初始化成员了吗? - liuyanghejerry
2
@liuyanghejerry 这里有两件不同的事情。首先是初始化,自 C++03 以来,对于整数类型,它允许在头文件中进行。正如您所看到的,这个 C++ 特性在 C++11 中被扩展到其他类型,只要它们是 constexpr 的。另一件事是为这些 const 成员分配内存空间。如果您获取这样一个变量的地址(&Fruit::VALUES[1]),它必须存在于某个地方。这个“某个地方”就是源文件中的这个定义。 - PiotrNycz
@liuyanghejerry 我不确定C++标准是否允许这样做,但在gcc中,只要您没有以任何方式使用该变量的地址,就可以在源文件中跳过对其定义 - 但这并不容易 - 任何采用const引用的函数都会强制编译器查找const变量的定义。 - PiotrNycz
你如何在C++03和C++11中都实现这个?我可以通过宏来隐藏constexpr,但我不知道如何同时初始化:(1)C++03的类外初始化和(2)C++11的类内初始化。 - jww
@jww #if __cplusplus < 201103L #define DECLARE_FRUIT_VALUES #define DEFINE_FRUIT_VALUES = { APPLE, ORANGE, BANANA, NONE } #else #define DECLARE_FRUIT_VALUES = { APPLE, ORANGE, BANANA, NONE } #define DEFINE_FRUIT_VALUES - PiotrNycz
@jww 的使用方式如下:static constexpr Value VALUES[4] DECLARE_FRUIT_VALUES; Value Fruit::Value[4] DEFINE_FRUIT_VALUES; - PiotrNycz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接