Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is in-class static const initialization of float different from int in C++?

I have a class with static const members that I'm initializing inside the class declaration:

#include <iostream>

class Foo
{
    public:
        static const int i = 9;
        static const float f = 2.9999;
};

int main()
{
    std::cout << Foo::i << std::endl;
    std::cout << Foo::f << std::endl;
    return 0;
}

When compiled with GCC 4.8.2 with option --std=c++11, it gives this compile error:

foo.cpp:7:32: error: ‘constexpr’ needed for in-class initialization of static data member ‘const float Foo::f’ of non-integral type [-fpermissive]
         static const float f = 2.9999;
                                ^

As the message indicates, the error goes away if the line is changed to static constexpr float f = 2.9999;.

Why should the in-class static const initialization of a floating-point variable be any different from a integral variable? Aren't they both just a value of certain size (number of bytes) that is copied over (like a macro) or referred to using a pointer?

Some older answers to similar (not the same) questions on SO indicate that this is because floating point expressions might give different results between the compiled machine and the execution machine (assuming a cross-compilation scenario).

However:

  1. the above code assigns a value directly, there is no arithmetic operation that needs to be performed to compute a value

  2. there might be different results for integral expressions too since its underflow and overflow results are not unambiguously defined across different architectures.

  3. Finally, what magic does constexpr do here that const does not? Why doesn't the language just do what constexpr does when const is used? I mean, why another keyword when the following statements work fine as C++ code outside a class anyway: const int i = 9; const float f = 2.9999;

like image 282
Ashwin Nanjappa Avatar asked Oct 13 '14 14:10

Ashwin Nanjappa


People also ask

How do you initialize static constant characteristics of a class?

For std::string , it must be defined outside the class definition and initialized there. static members must be defined in one translation unit to fulfil the one definition rule. If C++ allows the definition below; struct C { static const string b = "hi"; };

How do you initialize all type const data member during declaration?

To initialize the const value using constructor, we have to use the initialize list. This initializer list is used to initialize the data member of a class. The list of members, that will be initialized, will be present after the constructor after colon. members will be separated using comma.

What is const float in C++?

Floating-point constants specify values that must have a fractional part. Floating-point constants have a "mantissa," which specifies the value of the number, an "exponent," which specifies the magnitude of the number, and an optional suffix that specifies the constant's type(double or float).


1 Answers

It's just a limitation of the language, and one that has been addressed by the introduction of generalized constant expressions.

Since the original C++, only static class member constants of integral type can be initialized inline; this is the is same type restriction as for non-type template parameters. So you can combine the two like this:

struct MyTrait { static const int value = 10; };

template <int N> struct Foo;

Foo<MyTrait::value> foo;

In this usage, the static constant is not odr-used and no definition is required. I'm speculating, but I can imagine that this kind of use was the primary intention of allowing inline initialization. For all other types, you would presumably want to have a definition anyway, so you might as well put the initializer in the definition.

This isn't an excuse, of course, and I suppose the introduction of constexpr seeks to rectify this original narrow-mindedness.

like image 169
Kerrek SB Avatar answered Oct 22 '22 15:10

Kerrek SB