类型为double的静态类成员的常量表达式初始值设定项

Ste*_*ppo 16 c++ static-members constant-expression c++11 c++14

在C++ 11和C++ 14中,为什么我需要constexpr在以下代码段中:

class Foo {
    static constexpr double X = 0.75;
};
Run Code Online (Sandbox Code Playgroud)

而这个产生编译错误:

class Foo {
    static const double X = 0.75;
};
Run Code Online (Sandbox Code Playgroud)

(更令人惊讶的是)这个编译没有错误?

class Foo {
    static const double X;
};

const double Foo::X = 0.75;
Run Code Online (Sandbox Code Playgroud)

Sha*_*our 12

在C++ 03中,我们只允许为枚举类型的const积分的静态成员变量提供类初始化器,在C++ 11中,我们可以使用constexpr在类中初始化文本类型的静态成员.对于const变量,这个限制保留在C++ 11中,主要是为了兼容性C++ 03我们可以从封闭的问题1826看到这一点:常量表达式中的const浮点数表示:

用常量初始化的const整数可以用在常量表达式中,但是用常量初始化的const浮点变量不能.这是故意的,与C++ 03兼容,同时鼓励constexpr的一致使用.然而,有些人发现这种区别令人惊讶.

CWG最终以非缺陷(NAD)结束此请求,基本上说:

希望浮点值参与常量表达式的程序员应该使用constexpr而不是const.

作为参考N1804,9.4.2 [class.static.data]部分中公开提供的最接近C++ 03的标准草案说:

如果静态数据成员是const integer或const枚举类型,则它在类定义中的声明可以指定一个常量初始化器,它应该是一个整型常量表达式(5.19).在这种情况下,成员可以出现在整数常量表达式中.如果在程序中使用该成员,并且名称空间范围定义不包含初始化程序,则该成员仍应在名称空间作用域中定义.

和草案C++ 11标准部分9.4.2 [class.static.data]说:

如果非易失性const静态数据成员是整数类型或枚举类型,则其在类定义中的声明可以指定一个大括号或大小为初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式(5.19) .可以使用constexpr说明符在类定义中声明文字类型的静态数据成员; 如果是这样,它的声明应指定一个大括号或等于初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式.[...]

这在C++ 14标准草案中几乎相同.