首页 文章

为什么在类中初始化的非整数静态数据成员必须是constexpr?

提问于
浏览
19

在类定义中初始化的静态整数数据成员可以声明为 constconstexpr ,但在类定义中初始化的非整数静态数据成员必须是 constexpr

class MyClass {
  static const     int   w = 5;          // okay
  static constexpr int   x = 5;          // okay
  static const     float y = 1.5;        // error!
  static constexpr float z = 1.5;        // okay
};

有人知道为什么不允许y的声明吗?标准中将其定为非法的部分是9.4.2 / 3,但为什么它是非法的?

3 回答

  • 2

    在C 11之前,您无法在类声明中初始化非整数/枚举类型的静态成员(但您可以在类声明之外) . 管理 constexpr 的规则带有前向,但允许您在类声明中使用 constexpr 初始化它(因此您不再需要如下代码):

    struct A
    {
        static const float pi;
    };
    
    const float A::pi = 3.1415;
    

    这条规则的一个副作用是简化你的类结构,而不是让它变得丑陋(如上面的代码) .

    在C11添加 constexpr 之前的情况之一的原因之一是标准未指定如何实现浮点(它留给处理器/架构 - 例如,当你说 float x = 1.6f 时,它实际上是 1.6000000000024 在大多数系统上) .

  • 0

    float 有点难以描述其动机,但想象一下 class 成员:

    class MySpecialInt {
    public:
        constexpr MySpecialInt(const int & other) {
        }
    };
    class MyClass {
        static const     MySpecialInt a = 5; // error
        static constexpr MySpecialInt b = 5; // okay
    };
    

    在这种情况下, a 可能会有一些非平凡的结构,可能会违反(或至少非常复杂)单定义规则 . 因为 constexpr 已经保证了限制性编译时属性, b 的复制构造函数也必须是 constexpr ,因此保证在编译时返回一个定义良好的值(并且 NOT 违反了one-definition-rule)

    为什么 float 表现出这种行为我认为只是出于遗留原因,因为 float 从来没有传统上像这样初始化("because the standard says so"),所以他们在 constexpr 的保护下 grab 了初始化 static const float 成员 .

  • 4

    这可能是因为非整数i也可能包含像char这样的数据类型,这就是为什么你不能使它们保持不变并需要常量表达的原因 . 但是在积分的情况下,你可以使它们成为常量表达式或常量 . 因此,由于char只能是常量表达式,因此对于所有非整数值都是非法的 .

相关问题