C++中的静态常量初始化,float和int有什么不同?

6

我有一个类,其中包含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;
}

使用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;
                                ^

正如消息所示,如果将行更改为static constexpr float f = 2.9999;,错误就会消失。
为什么类内部浮点变量的静态常量初始化与整数变量有所不同?它们不都只是某个大小(字节数)的值(像宏一样)被复制或使用指针引用吗?
在 SO 上类似问题的早期答案表明,这是因为浮点表达式可能在编译机器和执行机器之间产生不同的结果(假设交叉编译场景)。
然而:
  1. 上述代码直接赋值,无需执行计算值的算术操作

  2. 对于整数表达式,由于下溢和上溢的结果在不同的架构之间没有明确定义,因此可能会有不同的结果。

  3. 最后,constexpr 在这里做了什么神奇的事情,const 没有做到的呢? 为什么语言不能在使用 const 时自动执行 constexpr 的操作呢?我的意思是,当以下语句作为 C++ 代码在类外部工作正常时,为什么还需要另一个关键字: const int i = 9; const float f = 2.9999;


@chris:为什么C++11不能像constexpr一样处理const语句,而是要求用户使用一个新的关键字呢? - Ashwin Nanjappa
你尝试过使用 static const float f = 2.9999f 吗? - barak manos
@barakmanos:尝试过了,还是同样的错误信息。 - Ashwin Nanjappa
1
就我所知,我查看了“constexpr”提案(N2235),其中包括这个:http://i.imgur.com/QdaqXTN.png - chris
为什么要加 'emacs' 标签?这个问题与 Emacs 有什么关系? - Drew
显示剩余2条评论
1个回答

1
这只是语言的一个限制,并且已经通过引入广义常量表达式得到解决。
自原始C++开始,只有整数类型的静态类成员常量可以内联初始化; 这与非类型模板参数的类型限制相同。因此您可以像这样将两者组合在一起:
struct MyTrait { static const int value = 10; };

template <int N> struct Foo;

Foo<MyTrait::value> foo;

在这种用法中,静态常量未被odr使用,因此不需要定义。我在推测,但我可以想象这种用法是允许内联初始化的主要意图。对于所有其他类型,您可能仍然希望有一个定义,因此最好将初始化程序放在定义中。
当然,这并不是借口,我认为引入constexpr旨在纠正这种最初的狭隘想法。

1
在原始的C++中,无法内联初始化静态类成员。这是C++98的一项创新。 - James Kanze
@JamesKanze:我认为这是“原创”的 :-) - Kerrek SB
2
在那之前,我已经使用C++编程近10年了。第一个广泛传播的规范将是1985年的《C++程序设计语言》。 - James Kanze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接