Why aren't static const floats allowed?

C++Visual C++

C++ Problem Overview


I have a class which is essentially just holds a bunch of constant definitions used through my application. For some reason though, longs compile but floats do not:

class MY_CONSTS
{
public :
	static const long   LONG_CONST = 1;      // Compiles 
	static const float FLOAT_CONST = 0.001f; // C2864
};

Gives the following error:

1>c:\projects\myproject\Constant_definitions.h(71) : error C2864: 'MY_CONSTS::FLOAT_CONST' : only static const integral data members can be initialized within a class

Am I missing something?

C++ Solutions


Solution 1 - C++

To answer the actual question you asked: "because the standard says so".

Only variables of static, constant, integral types (including enumerations) may be initialized inside of a class declaration. If a compiler supports in-line initialization of floats, it is an extension. As others pointed out, the way to deal with static, constant, non-integral variables is to define and initialize them in the class's corresponding source file (not the header).

C++ Standard Section 9.2 "Class Members" item 4:

> A member-declarator can contain a > constant-initializer only if it declares a static member (9.4) of > const integral or const enumeration > type, see 9.4.2.

Section 9.4.2 "Static Data Members" item 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 (5.19). In that case, the > member can appear in integral constant > expressions. The member shall still be > defined in a namespace scope if it is > used in the program and the namespace > scope definition shall not contain an > initializer.

Solution 2 - C++

You should initialize them in the body of one of your cpp files:

class MY_CONSTS
{
public :
    static const long   LONG_CONST = 1;      // Compiles 
    static const float FLOAT_CONST;
};

const float MY_CONSTS::FLOAT_CONST = 0.001f;

Solution 3 - C++

See Stroustrup's explanation. Relevant quote:

> A class is typically declared in a > header file and a header file is > typically included into many > translation units. However, to avoid > complicated linker rules, C++ requires > that every object has a unique > definition. That rule would be broken > if C++ allowed in-class definition of > entities that needed to be stored in > memory as objects. See D&E for an > explanation of C++'s design tradeoffs.

Solution 4 - C++

The rationale under the standard wording that others have given is the same for which template arguments can't be floating point number. To get consistent result you'll need the compiler implement the same evaluation as the one done at compile time, and that can be complicated for cross-compiler and in the case where the program plays with rounding mode.

From memory, in C++0X, the notion of constant expression has been extended and so your code would be valid (but it is unspecified in the result of floating point constant expressions are the same when evaluated at run-time or at compile time).

Solution 5 - C++

what about:

class MY_CONSTS
{
public :
    static const long   LONG_CONST;
    static const float FLOAT_CONST;
};

const long MY_CONSTS::LONG_CONST = 1;
const float MY_CONSTS::FLOAT_CONST = 0.001f;

(though, i cannot give any explanation of this specific case...)

Solution 6 - C++

From standard 9.4.2/4

> 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 (5.19). > In that case, the member can appear in > integral constant expressions. The > member shall still be defined in a > namespace scope if it is used in the > program and the namespace scope > definition shall not contain an > initializer.

And 5.19/1:

> In several places, C + + requires > expressions that evaluate to an > integral or enumeration constant: as > array bounds (8.3.4, 5.3.4), as case > expressions (6.4.2), as bit-field > lengths (9.6), as enumerator > initializers (7.2), as static member > initializers (9.4.2), and as integral > or enumeration non-type template > arguments (14.3). constant-expression: > conditional-expression An integral > constant-expression can involve only > literals (2.13), enumerators, const > variables or static data members of > integral or enumeration types > initialized with constant expressions > (8.5), non-type template parameters of > integral or enumeration types, and > sizeof expressions. Floating > literals (2.13.3) can appear only if > they are cast to integral or > enumeration types. Only type > conversions to integral or enumeration > types can be used. In particular, > except in sizeof expressions, > functions, class objects, pointers, or > references shall not

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
QuestionJon CageView Question on Stackoverflow
Solution 1 - C++Tyler McHenryView Answer on Stackoverflow
Solution 2 - C++WillView Answer on Stackoverflow
Solution 3 - C++JRLView Answer on Stackoverflow
Solution 4 - C++AProgrammerView Answer on Stackoverflow
Solution 5 - C++Adrien PlissonView Answer on Stackoverflow
Solution 6 - C++Andreas BrinckView Answer on Stackoverflow