Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/148.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么类中初始化的非整数静态数据成员必须是constexpr?_C++_C++11_Static Members_Constexpr - Fatal编程技术网

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

C++ 为什么类中初始化的非整数静态数据成员必须是constexpr?,c++,c++11,static-members,constexpr,C++,C++11,Static Members,Constexpr,在类定义中初始化的静态整型数据成员可以声明为const或constepr,但在类定义中初始化的非整型静态数据成员必须是constepr: class MyClass { static const int w = 5; // okay static constexpr int x = 5; // okay static const float y = 1.5; // error! static constex

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

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,但为什么它是非法的?

在C++11之前,不能在类声明中初始化非整数/枚举类型的静态成员(但可以在类声明之外)。管理
constexpr
的规则继承了这一点,但允许您在类声明中使用
constexpr
对其进行初始化(因此您不再需要下面这样的代码):

此规则的一个副作用是简化类结构,而不是使其难看(如上面的代码)


在C++11添加
constepr
之前,出现这种情况的原因之一是标准没有指定浮点的实现方式(这取决于处理器/体系结构-例如,当您说
float x=1.6f
时,在大多数系统上实际上是
1.600000000024
).

这可能是因为非整数i也可能包含像char这样的数据类型,这就是为什么不能将它们设置为常量,并且需要常量表达式。但是在整数的情况下,可以将它们设置为常量表达式或常量。因此,由于char只能是一个常量表达式,因此它对于所有非整数值都是非法的。

float
更难描述其动机,但想象一个类成员:

class MySpecialInt {
public:
    constexpr MySpecialInt(const int & other) {
    }
};
class MyClass {
    static const     MySpecialInt a = 5; // error
    static constexpr MySpecialInt b = 5; // okay
};
a
在这个场景中可能有一些非平凡的构造,可能违反(或至少严重复杂化)一个定义规则。因为
constepr
保证了限制性编译时属性,
b
的复制构造函数也必须是
constepr
,因此保证在编译时返回定义良好的值(并且不违反一个定义规则)


为什么
float
表现出这种行为,我认为这只是因为遗留的原因,因为
float
传统上从来没有像这样可以初始化(“因为标准这么说”),所以他们抓住了初始化
static
const
float
成员的机会,在
constexpr
历史、遗产、进化、传统的保护伞下?你看了吗?@gabriel.:你链接到的答案似乎是一个涉及C++98的讨论,不是C++11。我想了解更多关于ODR如何将其融入其中的细节。
a
b
中的每一个都必须初始化一次。这意味着必须只调用一次相应的构造函数。在
a
的情况下,我们不知道编译期间或运行时是否会发生构造,但在什么条件下可以多次定义
a
b
、或
myspecial
构造函数(这是由于使用了
constepr
const
)?它们实际上是每个翻译单元定义一次。因此,如果将该类包含在两个点中,
a
b
会被定义两次,但由于
b
constepr
,因此保证其值一致,因此是合法的
a
可能有一些内部计数器或其他逻辑,会导致翻译单元之间的
a
不同,这就是为什么仅将其声明为
静态
是非法的。根据9.4.2/3,带有初始值设定项的静态数据成员的声明不是定义,如果使用odr,则此类成员的定义必须在类之外。但您提到的问题(如果存在的话)同样适用于
const
——而不是
constepr
——动态初始化的整型成员。为产生初始化值而调用的函数在不同的调用中可能返回不同的值。所以我不明白这是如何解释非整型静态数据成员的限制的。在同一节中,它指出整型类型的初始值设定项子句必须都是常量表达式,因此它们本质上不能动态初始化。好的,但相同的限制适用于常量静态数据成员,因此,如果
a
的声明是合法的,
MySpecialInt
的构造函数仍然必须是
constexpr
。如果是这样的话,我们仍然不清楚(至少对我来说)为什么
constepr
可以,但是
const
不行。我一定还是漏掉了什么。你的想法是对的,但是一个坏例子。1.5f可以用二进制或十进制浮点类型精确表示,并且在几乎任何系统上都应该精确地存储为1.5。@hvd整个要点是,您不能依赖于它,因为它依赖于平台。您写道“在大多数系统上,它实际上是1.49999999999”,这不仅仅意味着它不需要准确地存储。如果您发现任何系统没有准确地存储它,我会非常惊讶,即使您是对的,它是允许的。@hvd如果它让您感觉更好,请用1.6f和1.600000024替换它。这是我在第一篇评论中试图指出的,你的观点是正确的,这只是一个没有(在典型实现中)说明这一点的例子。你现在提到的1.6f确实如此。
class MySpecialInt {
public:
    constexpr MySpecialInt(const int & other) {
    }
};
class MyClass {
    static const     MySpecialInt a = 5; // error
    static constexpr MySpecialInt b = 5; // okay
};