在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;
答案 0 :(得分:9)
在C ++ 03中,我们只允许为枚举类型的const积分的静态成员变量提供类初始化器,在C ++ 11中,我们可以使用constexpr在类中初始化文字类型的静态成员。对于const变量,这个限制保存在C ++ 11中,主要是为了兼容C ++ 03,我们可以从closed issue 1826: const floating-point in constant expressions 看到这一点:
用常量初始化的const整数可以用在常量表达式中,但是用常量初始化的const浮点变量不能。这是故意的,与C ++ 03兼容,同时鼓励constexpr的一致使用。然而,有些人发现这种区别是令人惊讶的。
CWG最终关闭此请求而不是缺陷( NAD ),基本上说:
希望浮点值参与常量表达式的程序员应该使用constexpr而不是const。
对于参考N1804
,9.4.2
[class.static.data] 部分中公开提供的最接近C ++ 03的标准草案说:
如果静态数据成员是const integral或const枚举类型,则它在类定义中的声明可以 指定一个常量初始化器,它应该是一个整型常量表达式(5.19)。在这种情况下,会员可以出现 在积分常数表达式中。如果在程序中使用该成员,则该成员仍应在命名空间范围内定义 命名空间范围定义不应包含初始化程序。
和草案C ++ 11标准部分9.4.2
[class.static.data] 说:
如果非易失性const静态数据成员是整数或枚举类型,则其在类中声明 definition可以指定一个大括号或者相等的初始化程序,其中每个initializer子句都是赋值表达式 是一个常量表达式(5.19)。可以在。中声明文字类型的静态数据成员 使用constexpr说明符的类定义;如果是这样,其声明应指定一个支撑或等于初始化器 其中作为赋值表达式的每个initializer子句都是一个常量表达式。 [...]
这在C ++ 14标准草案中几乎相同。
答案 1 :(得分:0)
类内静态const“定义”实际上是声明。当定义一个变量时,编译器会为该变量分配内存,但这不是这种情况,即获取这些静态const-in-class内容的地址是错误的,NDR。
这些东西应该用在代码中,但是浮点类型并不容易,因此不允许这样做。
通过在类外部定义静态const变量,您向编译器发信号通知这是真正的定义 - 具有内存位置的真实实例。