值初始化枚举的行为 [英] The behavior of value-initializing an enum

查看:187
本文介绍了值初始化枚举的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我想说,根据cppreference.com,它是有点不可能的值初始化枚举。



根据 http://en.cppreference.com/w/cpp/language/value_initialization ,值初始化枚举实际上执行零初始化。然后,根据 http://en.cppreference.com/w/cpp/language/zero_initialization,零初始化枚举的效果是:


如果 T 是标量类型,对象的初始值是隐式转换为 T 的积分常量零。


但是,整数常量零不能隐式转换为枚举。最终,枚举不能被值初始化。这听起来很奇怪,价值初始化一个枚举在VC,GCC和clang工作。



其次,根据 http://en.cppreference.com/w/cpp/language/static_cast


整数,浮动点或枚举类型可以转换为任何完整的枚举类型(结果未指定(直到C ++ 17)未定义的行为(自C ++ 17)如果表达式的值转换为枚举的底层类型,则不是其中一个目标枚举值)


因此,这意味着值初始化一个枚举如果目标枚举没有等于 0

解决方案的枚举符, div>

这个问题的答案在评论中给出。

要对零初始化对象或引用进行 T 表示:




  • 如果 code>是标量类型(3.9),对象被初始化为值
    ,通过将整数文本 0 (零)转换为 T ;


(枚举是标量类型; §3.9/ 9)
因为转换不是隐式的,我们不是在§4,而是在§5.2.9;


表达式 static_cast< T>(v)的结果是结果
将表达式 v 转换为 T




§5.2.9/ 10然后定义如何将整数值转换为枚举类型。


整数或枚举类型的值可以显式转换为
枚举类型。 如果原始值在枚举值(7.2)的范围内为
,则值不变。否则,结果
值未指定(可能不在该范围内)。


必须显示零在所有枚举的枚举值范围内。

接下来的五个引号取自§7.2/ 8:


对于其底层类型是固定的枚举,
枚举的值是底层类型的值。


由于所有允许的底层类型在其值域*中包含零,因此这会自动提供所需的结果。现在,对于没有固定底层类型的枚举,


否则,对于 e min 是最小的
枚举并且 e max 是最大的,
枚举的值是 b min b
max
,定义如下:




我们必须表明 b min 始终小于或等于零,并且 b max 或等于零。


K 为1表示二的
补码表示,一个补码或
符号幅度表示。

b max 是大于或等于 max(| e min | -K,| e max |) ,其中
M 是非负整数。


sub> max | 是非负数,最多两个数字至少与两个数字一样大。因此,max(| e min | -K,| e max |)也是非负的,并且 b max 必须大于或等于该数字 - 因此我们满足了第一个要求。


如果 e min 是非负数,并且 - (b max

显然是零或负数: b max 如上所示是非负数,并且 K 是非负数(0或1)因此它们的和的加性反比是非正的。我们的第二个要求得到满足。最后,


如果 enumerator-list 为空,
枚举的值为如果枚举有一个枚举值
value 0

$


通过设置 e min = e max = 0 ,可以得到上述结果。







  • 这减少为声明所有积分类型在其值的范围内具有零,这留给读者证明。 li>

First, I want to say, according to cppreference.com, it is somewhat impossible to value-initialize an enum.

According to http://en.cppreference.com/w/cpp/language/value_initialization, value-initializing an enum actually performs zero-initialization. It then follows that, according to http://en.cppreference.com/w/cpp/language/zero_initialization, the effect of zero-initializing an enum is:

If T is a scalar type, the object's initial value is the integral constant zero implicitly converted to T.

However, an integral constant zero is not implicitly convertible to an enum. Ultimately, an enum cannot be value-initialized. This sounds weird, and value-initializing an enum does work on VC, GCC, and clang. So, what does the standard say about this?

Second, according to http://en.cppreference.com/w/cpp/language/static_cast:

Integer, floating-point, or enumeration type can be converted to any complete enumeration type (the result is unspecified (until C++17) undefined behavior (since C++17) if the value of expression, converted to the enumeration's underlying type, is not one of the target enumeration values)

So, does this imply that value-initializing an enum (if it works at all) may actually lead to undefined behavior if the target enum does not have an enumerator equal to 0?

解决方案

The answer to this was given in the comments. My attempt of explaining the entire standardese behind it is given below.

To zero-initialize an object or reference of type T means:

  • if T is a scalar type (3.9), the object is initialized to the value obtained by converting the integer literal 0 (zero) to T;

(Enumerations are scalar types; §3.9/9) So as the conversion is not said to be implicit, we're not looking in §4, but §5.2.9;

The result of the expression static_cast<T>(v) is the result of converting the expression v to type T.

§5.2.9/10 then defines how integral values are converted to enumeration types.

A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the resulting value is unspecified (and might not be in that range).

It must be shown that zero is in the range of enumeration values for all enumerations.
The next five quotes are taken from §7.2/8:

For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type.

Since all permitted underlying types include zero in their range of values*, this automatically gives the desired result. Now, for enumerations without fixed underlying types,

Otherwise, for an enumeration where emin is the smallest enumerator and e max is the largest, the values of the enumeration are the values in the range b min to b max , defined as follows:

I.e. we have to show that bmin is always less than or equal to zero, and bmax is always greater or equal to zero.

Let K be 1 for a two’s complement representation and 0 for a one’s complement or sign-magnitude representation.
b max is the smallest value greater than or equal to max(|e min| − K, |e max|) and equal to 2M − 1, where M is a non-negative integer.

|e max| is non-negative, and the maximum of two numbers is at least as large as both numbers are. Hence max(|e min| − K, |e max|) is non-negative as well, and bmax must be greater or equal to that number - so our first requirement is met.

b min is zero if emin is non-negative and −(bmax + K) otherwise.

bmin is clearly either zero or negative: bmax is non-negative as shown above, and K is non-negative (0 or 1), hence the additive inverse of their sum is non-positive. Our second requirement is met. Finally,

If the enumerator-list is empty, the values of the enumeration are as if the enumeration had a single enumerator with value 0.

This leads to the above result by setting emin = emax = 0.


  • This reduces to the claim "All integral types have zero in their range of values", which is left to prove for the reader.

这篇关于值初始化枚举的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆