Why I can't provide an in-class initializer for std::vector data member

Viewed 31

I'm trying to initialize the member vec within the class scope, but the compiler throws a more cryptic error.

class A {
public:
    static const size_t sz = 10;
    static const std::vector<double> vec{ sz }; // error
};

The compiler (gcc) gives the following error(s):

error: in-class initialization of static data member 'std::vector<double> A::vec' of non-literal type
   10 |     static std::vector<double> vec{ sz };
      |                                ^~~
error: non-constant in-class initialization invalid for non-inline static member 'A::vec'
   10 |     static std::vector<double> vec{ sz };
      |                                        ^
note: (an out of class initialization is required)

How I can fix this?

2 Answers

Ordinarily, static data members may not be initialized in the class body. However, we can provide in-class initializers for static members that are only of const-qualified integral type. If non-integral static members are used, and you need to provide an in-class initializer, the data member shall be constexpr literal type. In any case, the initializers must be constant expressions. If the type of the member is not literal type (hence constexpr can't be used), the static member shall not have a default member initializer, instead, it can be defined outside the class.

So your error is just because std::vector<double> is of non-integral type. Also, you can't declare vec as constexpr because std::vector<double> is not a literal type.

So to fix your above example, you can do this:

class A {
public:
    static const size_t sz = 10;
    static const std::vector<double> vec;
};

const std::vector<double> A::vec{ sz };

(Demo)

As pointed out in the commnets, note that, making vec const-qualified, you will lose some of the vector features. For example, you can't modify any element after adding it!

The problem is that std::vector is not an integral or an enumeration type. So the non-inline non-const static data member named vec cannot be initialized inside the class. This can be seen from constant static members:

If a static data member of integral or enumeration type is declared const (and not volatile), it can be initialized with an initializer in which every expression is a constant expression, right inside the class definition:

(emphasis mine)

And since std::vector is neither an integral nor an enumeration type , it cannot be initialized inside the class.


How I can fix this?

There are 2 ways of solving this.

Method 1: C++17

One option is to use the inline keyword from C++17 as shown below:

class A {
public:
    static const size_t sz = 10;
    //-----vvvvvv---------------------------------------->works with inline in c++17
    static inline const std::vector<double> vec{ sz }; 
};

Working demo

This works because:

A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify an initializer. It does not need an out-of-class definition:


Method 2: Prior C++17

Before c++17, you would have to provide an out of class definition:

class A {
public:
    static const size_t sz = 10;
    static const std::vector<double> vec; //this is a declaration
};

const std::vector<double> A::vec{ sz }; //this is a definition
Related