C++11 Initializing class static const array

14,603

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]

Compiler told what is missing:

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

cc1l4Xgi.o:test.cpp:(.text+0x1a): undefined reference to `Fruit::VALUES'

To make linker happy, you must add this line somewhere in source files (not header file):

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

EDIT: Since c++17 we have inline variables and each constexpr variable is inline, so in C++17 the problem is solved.

Share:
14,603
user1594322
Author by

user1594322

Updated on June 23, 2022

Comments

  • user1594322
    user1594322 almost 2 years

    Here's what I am trying. 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;
    }
    

    I try compiling it and get the output below:

    >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
    

    Is C++11 supposed to allow initializing a static const array in a class like this? Or does it have to be defined outside the class as before C++11?

  • liuyanghejerry
    liuyanghejerry over 11 years
    Hey, I have the same question but I'm wondering why do linkers need this line? Doesn't c++11 already support init members in class definition?
  • PiotrNycz
    PiotrNycz over 11 years
    @liuyanghejerry These are two separate things here. First is initialization and it is allowed in header for integer types since C++03. And as you can see, this C++ feature was extended in C++11 for other types as long as they are constexpr. The other thing is a room in memory for this const members. If you take an address of such variale (&Fruit::VALUES[1]) it must exists somewhere. This "somewhere" is just this definition in source file.
  • PiotrNycz
    PiotrNycz over 11 years
    @liuyanghejerry I am not sure if this is allowed by C++ std but in gcc you can skip this definition in source file as long as you do not use the address of this variable in any way - but this is not easy - any function taking const reference forces compiler to look for the const variable definition.
  • jww
    jww over 7 years
    How do you do this for both C++03 and C++11? I can hide constexpr behind a macro. But I don't know how to initialize both: (1) out-of-class for C++03, and (2) in-class C++11.
  • PiotrNycz
    PiotrNycz over 7 years
    @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
    PiotrNycz over 7 years
    @jww and use like this: static constexpr Value VALUES[4] DECLARE_FRUIT_VALUES; Value Fruit::Value[4] DEFINE_FRUIT_VALUES;