Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 uniform initialization: Field initializer is not constant

I'm trying to instantiate a set of strings like this:

class POI {
public:
...
  static const std::set<std::string> TYPES { "restaurant", "education", "financial", "health", "culture", "other" };
...
}

Now, when I do this I get these errors (all on this line):

error: field initializer is not constant
 static const std::set<std::string> TYPES { "restaurant", "education", "financial", "health", "culture", "other" };
error: in-class initialization of static data member 'const std::set<std::basic_string<char> > POI::TYPES' of non-literal type
error: non-constant in-class initialization invalid for static member 'POI::TYPES'                                                              
error: (an out of class initialization is required)
error: 'POI::TYPES' cannot be initialized by a non-constant expression when being declared

That would make sense to my eyes if I assumed that the strings inside the set are not treated as being const. Is that really the problem here? Unfortunately, I cannot find a way of declaring those strings inside the initializer as const.. Is that possible?

like image 750
Lukas Barth Avatar asked Dec 06 '22 20:12

Lukas Barth


2 Answers

You must initialize your static variable out-of-line, as in:

#include <set>
#include <string>

class POI {
public:
  static const std::set<std::string> TYPES;
};
const std::set<std::string> POI::TYPES { "restaurant", "education", "financial", "health", "culture", "other" };

This would work for an integral / enum type, as specified by the standard (section 9.4.2:)

If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression. In that case, the member can appear in integral constant expressions within its scope.

like image 111
serge-sans-paille Avatar answered Feb 08 '23 16:02

serge-sans-paille


Initializers in C++ were meant to be part of a definition, not of a declaration. This was relaxed for const integral and enum types. In C++11 further directives were added for constexpr members of literal type

[class.static.data]/p3

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression (5.20). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ ... ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer

Since it doesn't apply to your case, you should thus initialize your static variable out-of-line as shown in this example

class POI {
public:
  static const std::set<std::string> TYPES;
};

const std::set<std::string> POI::TYPES = {
   "restaurant", "education", "financial", "health", "culture", "other" 
};
like image 25
Marco A. Avatar answered Feb 08 '23 17:02

Marco A.