编译和工作的错误静态常量初始化
据我所知,您只能在声明的同一行中初始化静态常量成员如果它们是整数类型一>.但是,我仍然能够初始化并使用一些静态常量双打:
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 编译但 Foo2::C 变为 1,所以也许它被视为一个 int,因为它在数字上是 1.Foo3 和 Foo4 甚至没有按预期编译.但是,我不明白为什么 Foo1 既能编译又能正常工作.这种特定用法是否被接受?是不是因为一些优化?(我试过使用 -O1 和 -O0)
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)
注意:使用带有 cmake 的 GNU 5.2.0 并将标准设置为 C++98.切换到 C++11 工作正常(也就是说,不编译并要求将这些成员切换到 constexpr).
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).
推荐答案
Foo1
情况确实不符合标准,如果我们使用 -std=c++98 -pedantic
gcc 会发出如下警告(实时观看):
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]
虽然在没有 -pedantic
的情况下编译不会产生任何错误或警告 (现场观看)
While compiling without -pedantic
does not yield any error or warning (see it live)
所以这必须是一个扩展,如果我们使用 -std=C++98 -pedantic
使用 clang,我们会看到这条消息:
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.
这个浮点限制保留在 C++11 中以保持与 C++03 兼容并鼓励一致使用 constexpr 参见:double 类型的静态类成员的常量表达式初始值设定项.
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.
这也是 Foo2
初始化 C
允许作为扩展的情况,除法的结果将是 int 因为类型结果的大小取决于操作数的类型,而不取决于您将其分配给什么.
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.
更新
这是一个折旧的扩展:
G++ 允许在类定义中使用初始值设定项声明 const 浮点类型的静态数据成员.该标准只允许 const 整数类型和 const 枚举类型的静态成员的初始值设定项,因此此扩展已被弃用,并将从未来版本中删除.
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.
有一个更详细的 gcc 错误报告,讨论了扩展的有效性和其他相关问题.
There is a more detailed gcc bug report that discusses the validity of the extension and other related issues around it.
使用 -pedantic
本身就足以将其转变为错误似乎很奇怪,有一个 涵盖该内容的 gcc 错误报告.
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.
相关文章