51

The problem with the following code is static member of type "const double" cannot have an in-class initializer. Why is applicable only for a 'const double'in the following code? Please help me.

class sample{ static const char mc = '?'; static const double md = 2.2; static const bool mb = true; }; const char sample::mc; const double sample::md; const bool sample::mb; int main(){ } 

3 Answers 3

72

The logic implemented by the C++03 language standard is based on the following rationale.

In C++ an initializer is a part of object definition. What you write inside the class for static members is actually only a declaration. So, formally speaking, specifying initializers for any static members directly inside the class is "incorrect". It is contrary to the general declaration/definition concepts of the language. Whatever static data you declare inside the class has to be defined later anyway. That's where you will have your chance to specify the initializers.

An exception from this rule was made for static integer constants, because such constants in C++ can form Integral Constant Expressions (ICEs). ICEs play an important role in the language, and in order for them to work as intended the values of integral constants have to be visible in all translation units. In order to make the value of some constant visible in all translation units, it has to be visible at the point of declaration. To achieve that the language allows specifying the initializer directly in class.

Additionally, on many hardware platforms constant integer operands can be embedded directly into the machine commands. Or the constant can be completely eliminated or replaced (like, for example, multiplication by 8 can be implemented as a shift by 3). In order to facilitate generation of machine code with embedded operands and/or various arithmetical optimizations it is important to have the values of integral constants visible in all translation units.

Non-integral types do not have any functionality similar to ICE. Also, hardware platforms do not normally allow embedding non-integral operands directly into the machine commands. For this reason the above "exception from the rules" does not extend to non-integral types. It would simply achieve nothing.

Sign up to request clarification or add additional context in comments.

2 Comments

Why wasn't such exception from the rule made for doubles? Doesn't it make sense to embed floating constants into machine commands?
@anton_rh: Good question. I don't know why it wasn't allowed purely conceptually. As for practical considerations, most platforms simply couldn't embed floating-point constants (and still can't). And one reason for that might be the fact that floating-point constants are too large for such embedding. However, in C++11 constexpr allows you to work around that restriction at least conceptually.
37

The compiler offered me to use constexpr instead of const:

static_consts.cpp:3:29: error: ‘constexpr’ needed for in-class initialization of static data member ‘const double sample::md’ of non-integral type [-fpermissive] static_consts.cpp:7:22: error: ‘constexpr’ needed for in-class initialization of static data member ‘const double sample::md’ of non-integral type [-fpermissive] 

I've just accepted the offer:

class sample{ static const char mc = '?'; static constexpr double md = 2.2; static const bool mb = true; }; const char sample::mc; const bool sample::mb; int main(){ } 

And now it compiles just fine (C++11).

3 Comments

Your compiler is more helpful than my compiler (MSVC++)!
Great answer. Exactly what I was looking for. Thank you.
This doesn't explain why a static const has to be an integral type. Just that new versions of c++ allowed for static constexpr doubles.
15

Pre-C++11, only const integral types could be directly initialized in the class definition. It's just a restriction imposed by the standard.

With C++11, this no longer applies.

6 Comments

Actually, as per [class.static.data]p3, static data can still be initialised in the class definition only if it's non-volatile const of integral or enumeration type.
@Angew are you talking about "its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignmentexpression is a constant expression". Because that's different - it's about brace initialization.
How is that different? As per [dcl.init], brace-or-equal-initializer ::= = initializer-clause | braced-init-list
still can't compile this code with C++11 compiler and even with C++14 compiler.
@Luchian Grigore: As long as we are talking about static const specifically, there are no changes in C++11. Rules for static members remain virtually unchanged in that regard. static const double still cannot be initialized in-class, even in C++14. constexpr is a different story though - it supports immediate initializers.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.