Initializing const member within class declaration in C++

C++G++

C++ Problem Overview


In PHP and C# the constants can be initialized as they are declared:

class Calendar3
{
    const int value1 = 12;
    const double value2 = 0.001;
}

I have the following C++ declaration of a functor which is used with another class to compare two math vectors:

struct equal_vec
{
    bool operator() (const Vector3D& a, const Vector3D& b) const
    {
        Vector3D dist = b - a;
        return ( dist.length2() <= tolerance );
    }

    static const float tolerance = 0.001;
};

This code compiled without problems with g++. Now in C++0x mode (-std=c++0x) the g++ compiler outputs an error message:

> error: ‘constexpr’ needed for in-class initialization of static data member ‘tolerance’ of non-integral type

I know I can define and initialize this static const member outside of the class definition. Also, a non-static constant data member can be initialized in the initializer list of a constructor.

But is there any way to initialize a constant within class declaration just like it is possible in PHP or C#?

Update

I used static keyword just because it was possible to initialize such constants within the class declaration in g++. I just need a way to initialize a constant in a class declaration no matter if it declared as static or not.

C++ Solutions


Solution 1 - 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.

Solution 2 - C++

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.

Solution 3 - C++

Yes. Just add the constexpr keyword as the error says.

Solution 4 - C++

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.

Solution 5 - C++

If you only need it in the one method you can declare it locally static:

struct equal_vec
{
    bool operator() (const Vector3D& a, const Vector3D& b) const
    {
        static const float tolerance = 0.001f;
        Vector3D dist = b - a;
        return ( dist.length2() <= tolerance );
    }
};

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionezpressoView Question on Stackoverflow
Solution 1 - C++Anthony WilliamsView Answer on Stackoverflow
Solution 2 - C++FlorianView Answer on Stackoverflow
Solution 3 - C++StilesCrisisView Answer on Stackoverflow
Solution 4 - C++nilesOienView Answer on Stackoverflow
Solution 5 - C++Peter WoodView Answer on Stackoverflow