在C++中,float的类内静态const初始化如何与int不同?

Ash*_*ppa 6 c++ floating-point c++11

我有一个类static const,我正在类声明中初始化成员:

#include <iostream>

class Foo
{
    public:
        static const int i = 9;
        static const float f = 2.9999;
};

int main()
{
    std::cout << Foo::i << std::endl;
    std::cout << Foo::f << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当使用带有选项的GCC 4.8.2编译时--std=c++11,它会产生以下编译错误:

foo.cpp:7:32: error: ‘constexpr’ needed for in-class initialization of static data member ‘const float Foo::f’ of non-integral type [-fpermissive]
         static const float f = 2.9999;
                                ^
Run Code Online (Sandbox Code Playgroud)

如消息所示,如果更改行,则错误消失static constexpr float f = 2.9999;.

为什么浮点变量的类内静态const初始化与整数变量有什么不同?它们是否只是一个特定大小(字节数)的值被复制(如宏)或使用指针引用?

对SO的类似(不相同)问题的一些较旧的答案表明这是因为浮点表达式可能在编译的机器和执行机器之间给出不同的结果(假设交叉编译场景).

然而:

  1. 上面的代码直接赋值,没有需要执行的算术运算来计算值

  2. 由于其下溢和溢出结果不能在不同的体系结构中明确定义,因此积分表达式可能会有不同的结果.

  3. 最后,constexpr这里有什么魔法const呢?为什么语言不能像使用constexpr时那样做const?我的意思是,为什么另一个关键字,当下面的语句作为一个类外的C++代码正常工作: const int i = 9; const float f = 2.9999;

Ker*_* SB 1

这只是该语言的限制,并且已通过引入广义常量表达式来解决这一限制。

从最初的C++开始,只能内联初始化整型的静态类成员常量;这与非类型模板参数具有相同的类型限制。所以你可以像这样将两者结合起来:

struct MyTrait { static const int value = 10; };

template <int N> struct Foo;

Foo<MyTrait::value> foo;
Run Code Online (Sandbox Code Playgroud)

在这种用法中,静态常量不被使用,并且不需要定义。我在猜测,但我可以想象这种使用是允许内联初始化的主要目的。对于所有其他类型,您可能希望有一个定义,因此您不妨将初始值设定项放在定义中。

当然,这不是一个借口,我想它的引入constexpr旨在纠正这种最初的狭隘思想。

  • 在此之前大约 10 年前我就已经开始使用 C++ 进行编程了。第一个广泛传播的规范是 1985 年的第一个_C++ 编程语言_。 (2认同)