Initializing const member within class declaration in C++
In C++11, non-static
data members, static constexpr
data members, and static const
data members of integral or enumeration type may be initialized in the class declaration. e.g.
struct X {
int i=5;
const float f=3.12f;
static const int j=42;
static constexpr float g=9.5f;
};
In this case, the i
member of all instances of class X
is initialized to 5
by the compiler-generated constructor, and the f
member is initialized to 3.12
. The static const
data member j
is initialized to 42
, and the static constexpr
data member g
is initialized to 9.5
.
Since float
and double
are not of integral or enumeration type, such members must either be constexpr
, or non-static
in order for the initializer in the class definition to be permitted.
Prior to C++11, only static const
data members of integral or enumeration type could have initializers in the class definition.
Initializing static member variables other than const int types is not standard C++ prior C++11. The gcc compiler will not warn you about this (and produce useful code nonetheless) unless you specify the -pedantic
option. You then should get an error similiar to:
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]
The reason for this is that the C++ standard does not specifiy how floating point should be implemented and is left to the processor. To get around this and other limitations constexpr
was introduced.
Yes. Just add the constexpr
keyword as the error says.
I ran into real problems with this, because I need the same code to compile with differing versions of g++ (the GNU C++ compiler). So I had to use a macro to see which version of the compiler was being used, and then act accordingly, like so
#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;
This will use 'const' for everything before g++ version 6.0.0 and then use 'constexpr' for g++ version 6.0.0 and above. That's a guess at the version where the change takes place, because frankly I didn't notice this until g++ version 6.2.1. To do it right you may have to look at the minor version and patch number of g++, so see
https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
for the details on the available macros.
With gnu, you could also stick with using 'const' everywhere and then compile with the -fpermissive
flag, but that gives warnings and I like my stuff to compile cleanly.
Not great, because it's specific to gnu compilers, butI suspect you could do similar with other compilers.