错误的静态const初始化,编译和工作

Wrong static const initialization that compiles and works

本文关键字:编译 工作 初始化 静态 const 错误      更新时间:2023-10-16

据我所知,如果静态const成员是整型,则只能在声明的同一行初始化。但是,我仍然能够初始化和使用一些静态const double类型:

// 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可以编译,但是Foo2::C变成了1,所以它可能被视为int,因为它是数字1。正如预期的那样,Foo3和Foo4甚至不能编译。然而,我不明白为什么Foo1既编译和工作正确。这种特殊用法被接受吗?是因为一些优化吗?(我试过使用- 01和- 0)

注意:使用GNU 5.2.0和cmake并将标准设置为c++ 98。切换到c++ 11工作得很好(也就是说,不编译并要求将这些成员切换到constexpr)。

Foo1的情况确实不符合,如果我们使用-std=c++98 -pedantic构建,gcc将发出以下警告(查看它的实时):

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]

在没有-pedantic的情况下编译不会产生任何错误或警告(查看它的实时)

所以这必须是一个扩展,如果我们使用clang使用-std=C++98 -pedantic,我们看到这个消息:

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;
                    ^ ~~~

这似乎证实了这是一个扩展

在c++ 11中保留了对浮点数的限制,以保持与c++ 03的兼容,并鼓励constexpr的一致使用,参见:double类型静态类成员的常量表达式初始化式

这也是Foo2初始化C作为扩展允许的情况,除法的结果将是int,因为结果的类型取决于操作数的类型,而不取决于它的赋值对象。

更新

这是一个贬值的扩展:

c++允许在类定义中使用初始化式声明const浮点类型的静态数据成员。该标准只允许const整型和const枚举类型的静态成员的初始化式,因此该扩展已被弃用,并将从未来的版本中删除。

有一个更详细的gcc bug报告,讨论了扩展的有效性和其他相关问题。

看起来很奇怪,使用-pedantic本身就足以将此转换为错误,有一个gcc错误报告涵盖了这一点。

相关文章: