double类型静态类成员的常量表达式初始化项

Constant expression initializer for static class member of type double

本文关键字:表达式 初始化 常量 类型 静态类 成员 double      更新时间:2023-10-16

在c++ 11和c++ 14中,为什么在下面的代码片段中需要constexpr:

class Foo {
    static constexpr double X = 0.75;
};

而这个会产生编译错误:

class Foo {
    static const double X = 0.75;
};

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

class Foo {
    static const double X;
};
const double Foo::X = 0.75;

在c++ 03中,我们只允许为枚举类型的const整型静态成员变量提供类内初始化器,在c++ 11中,我们可以在类中使用constexpr初始化文字类型的静态成员。c++ 11中对const变量保留了这个限制,主要是为了与c++ 03兼容。我们可以从关闭的第1826号问题中看到这一点:常量表达式中的const浮点数说:

用常量初始化的const整型可用于常量表达式,但用常量初始化的const浮点变量不能用于常量表达式。这是有意为之,为了与c++ 03兼容,同时鼓励一致地使用constexpr。然而,有些人发现这种区别令人惊讶。

CWG最终关闭了这个请求,认为它不是一个缺陷(NAD),基本上说:

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

参考N1804,最接近c++ 03的标准草案在9.4.2 [class.static]部分公开。数据]说:

如果静态数据成员是const整型或const枚举类型,则在类定义中的声明可以指定一个常量初始化式,该初始化式必须是一个整型常量表达式(5.19)。在这种情况下,成员可以出现在积分常数表达式中。如果成员在程序和程序中使用,则该成员仍应在命名空间作用域中定义命名空间作用域定义不能包含初始化式。

和c++ 11标准草案9.4.2 [class.static]。数据]说:

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

类内静态const "定义"实际上是声明。当定义一个变量时,编译器会为该变量分配内存,但这里的情况并非如此,也就是说,获取这些静态类中常量的地址是不正确的,即NDR。

这些东西应该被处理到代码中,但是对于浮点类型来说,这不是那么容易做到的,因此不允许。

通过在类之外定义静态const变量,您向编译器发出信号,表明这是真正的定义-具有内存位置的真实实例。