Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
433 views
in Technique[技术] by (71.8m points)

c++ - Wrong static const initialization that compiles and works

As far as I know, you can only initialize static const members in the same line of their declaration if they are integral types . However, I was still able to initialize and use some static const doubles:

// compiles and works, values are indeed doubles
struct Foo1{ 
    static const double A=2.5;
    static const double B=3.2;
    static const double C=1.7;
};

// compiles, but values are cast to int
struct Foo2{
    static const int A=2;
    static const int B=3;
    static const double C=B/A; //becomes 1
};

// does not compile, Foo3::B cannot appear in a constant-expression
struct Foo3{ 
    static const int A=2;
    static const double B=3;
    static const double C=A/B; 
};

// does not compile, a cast to a type other than an integral or enumeration
// cannot appear in a constant-expression
struct Foo4{ 
    static const int A=2;
    static const int B=3;
    static const double C=(double)A/B; 
};

Foo2 compiles but Foo2::C becomes 1, so maybe it is treated as an int as it is numerically one. Foo3 and Foo4 don't even compile, as expected. However, I don't understand why Foo1 both compiles and works correctly. Is this specific usage accepted? Is it because of some optimization? ( I've tried using -O1 and -O0)

Note: using GNU 5.2.0 with cmake and setting the standard to C++98. Switching to C++11 works fine ( that is, does not compile and asks to switch those members to constexpr).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The Foo1 case is indeed non-conforming and if we build using -std=c++98 -pedantic gcc will warn as follows (see it live):

error: floating-point literal cannot appear in a constant-expression
 static const double A=2.5;
                       ^
warning: ISO C++ forbids initialization of member constant 'Foo1::A' of non-integral type 'const double' [-Wpedantic]

While compiling without -pedantic does not yield any error or warning (see it live)

So this must be an extension and if we use clang using -std=C++98 -pedantic we see this message:

warning: in-class initializer for static data member of type 'const double' is a GNU extension [-Wgnu-static-float-init]
static const double A=2.5;
                    ^ ~~~

which seems to confirm this is an extension.

This restriction on floating point was kept in C++11 to remain compatible with C++03 and to encourage consistent use of constexpr see: Constant expression initializer for static class member of type double.

This is also the case for Foo2 initializing C is allowed as an extension, the result of the division will be int since the type of the result depends on the type of the operands and does not depend on what you assign it to.

Update

This is a depreciated extension:

G++ allows static data members of const floating-point type to be declared with an initializer in a class definition. The standard only allows initializers for static members of const integral types and const enumeration types so this extension has been deprecated and will be removed from a future version.

There is a more detailed gcc bug report that discusses the validity of the extension and other related issues around it.

It seemed odd that using -pedantic was sufficient by itself to turn this into an error, there is a gcc bug report that covers that.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...