开发者

Why aren't static const floats allowed? [duplicate]

开发者 https://www.devze.com 2022-12-23 15:49 出处:网络
This question already has answers here: Why can't I have a non-integral static const member in a class?
This question already has answers here: Why can't I have a non-integral static const member in a class? (5 answers) Closed 5 months ago.

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?


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.


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;


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.


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).


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...)


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


In C++11 and later, you can use constexpr to define class float constants:

class MY_CONSTS
{
public:
    static constexpr long  LONG_CONST = 1;      
    static constexpr float FLOAT_CONST = 0.001f;
};
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号