是否可以将枚举类变量reinterpret_cast转换为基础类型的引用? [英] Is it safe to reinterpret_cast an enum class variable to a reference of the underlying type?
问题描述
我见过 reinterpret_cast
用于对枚举类应用增量,我想知道在标准C ++中这种用法是否可以接受。
枚举类Foo:int8_t
{
Bar1,
Bar2,
Bar3,
Bar4,
First = Bar1,
Last = Bar4
};
for(Foo foo = Foo :: First; foo< = Foo :: Last; ++ reinterpret_cast< int8_t&>(foo))
{
。 ..
}
我知道转换为基类的引用是安全的的小类。但是由于枚举类不是隐式转换为它们的底层类型,我不知道上面的代码是否和如何保证在所有编译器中工作。任何线索?
您可能想重载operator ++
您的枚举,如果你真的想迭代其值:
Foo& operator ++(Foo& f)
{
使用UT = std :: underlying_type< Foo> :: type;
f = static_cast< Foo>(static_cast< UT>(f)+1);
return f;
}
并使用
for(Foo foo = Foo :: First; foo!= Foo :: Last; ++ foo)
{
...
} b $ b
要回答 reinterpret_cast
是允许的,它全部从5.2.10 / 1开始:
5.2.10重新解释转换[expr.reinterpret.cast]
1 表达式
reinterpret_cast< T&
是将表达式v
转换为T
的结果。如果T
是一个左值引用类型或对函数类型的右值引用,结果是一个左值;如果T
是对象类型的右值引用,则结果是xvalue;否则,结果为prvalue,并对表达式v执行标准值转换(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换
。 可以使用reinterpret_cast
显式执行的转换如下所示。使用reinterpret_cast
可以明确执行其他转换。
(强调我)
使用引用的重新解释是基于5.2.10 / 11的指针:
11 类型
T1
的glvalue表达式可以转换为T2
可以显式转换为指向T2
的类型的指针 code>使用reinterpret_cast
。结果引用与源glvalue相同的对象,但具有指定的类型。 [注意:也就是说,对于左值,引用reinterpret_cast< T&>(x)
使用内置的&
和来创建一个c $ c> * reinterpret_cast< T *>(& x)*
运算符(对于reinterpret_cast< T&&>(x)
)也类似。 - 结束注释]未创建任何临时,不进行任何复制,不会调用构造函数(12.1)或转换函数(12.3)。
这会转换问题:
reinterpret_cast< int8_t&>(foo)
是否合法:
* reinterpret_cast
stop是5.2.10 / 7:
7 一个对象指针可以被显式转换为一个对象指针不同类型。当指向
T1
类型的prvaluev
被转换为指向 cvT2
,结果是static_cast
T1 和cv
T2 *>(static_cast<
cv
T2
void *>(v)) >是标准布局类型(3.9),T2
的对齐要求不比T1
的对齐要求更严格,如果任一类型是void
。将指向T2
的类型指针的类型转换为类型指针c> T1
和T2
是对象类型,其中T2
的对齐要求比T1
更严格)并返回到其原始类型,产生原始指针值。
给定3.9 / 9两个 int8_t
和您的枚举类型是标准布局类型,现在的问题转换为:
* static_cast< int8_t *>(static_cast< ; void *>(& foo))
这是你运气不好的地方。 static_cast
在5.2.9中定义,没有什么使上述合法 - 事实上5.2.9 / 5是一个明确的暗示,它是非法的。其他条款没有帮助:
- 5.2.9 / 13需要
T *
- >void - >
- >
必须相同(省略 cv )
- 5.2.9 / 9和5.2.9 / 10不是指针,而是值
- 5.2.9 / 11是关于类和类层次结构
- 5.2.9 / 12是关于类成员指针
我的结论是你的代码
reinterpret_cast< int8_t&> )
不合法,其行为未由标准定义。
还要注意,上面提到的5.2.9 / 9和5.2.9 / 10负责使代码合法,我在初始答案中给出,你仍然可以在顶部找到。 / p>
I've seen reinterpret_cast
used to apply incrementation to enum classes, and I'd like to know if this usage is acceptable in standard C++.
enum class Foo : int8_t
{
Bar1,
Bar2,
Bar3,
Bar4,
First = Bar1,
Last = Bar4
};
for (Foo foo = Foo::First; foo <= Foo::Last; ++reinterpret_cast<int8_t &>(foo))
{
...
}
I know casting to a reference of a base class is safe in case of trivial classes. But since enum classes are not event implicitly converted to their underlying types, I'm not sure if and how the code above would be guaranteed to work in all compilers. Any clues?
You might want to overload operator ++
for your enum if you really want to iterate its values:
Foo& operator++( Foo& f )
{
using UT = std::underlying_type< Foo >::type;
f = static_cast< Foo >( static_cast< UT >( f ) + 1 );
return f;
}
and use
for (Foo foo = Foo::First; foo != Foo::Last; ++foo)
{
...
}
To answer the question of whether or not the reinterpret_cast
is allowed, it all starts with 5.2.10/1:
5.2.10 Reinterpret cast [expr.reinterpret.cast]
1 The result of the expression
reinterpret_cast<T>(v)
is the result of converting the expressionv
to typeT
. IfT
is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; ifT
is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue and the lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the expressionv
. Conversions that can be performed explicitly usingreinterpret_cast
are listed below. No other conversion can be performed explicitly usingreinterpret_cast
.
(emphasis mine)
The reinterpretation using references is based on pointers as per 5.2.10/11:
11 A glvalue expression of type
T1
can be cast to the type "reference toT2
" if an expression of type "pointer toT1
" can be explicitly converted to the type "pointer toT2
" using areinterpret_cast
. The result refers to the same object as the source glvalue, but with the specified type. [ Note: That is, for lvalues, a reference castreinterpret_cast<T&>(x)
has the same effect as the conversion*reinterpret_cast<T*>(&x)
with the built-in&
and*
operators (and similarly forreinterpret_cast<T&&>(x)
). — end note ] No temporary is created, no copy is made, and constructors (12.1) or conversion functions (12.3) are not called.
Which transforms the question from this:
reinterpret_cast<int8_t&>(foo)
to whether this is legal:
*reinterpret_cast<int8_t*>(&foo)
Next stop is 5.2.10/7:
7 An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue
v
of type "pointer toT1
" is converted to the type "pointer to cvT2
", the result isstatic_cast<
cv
T2*>(static_cast<
cv
void*>(v))
if bothT1
andT2
are standard-layout types (3.9) and the alignment requirements ofT2
are no stricter than those ofT1
, or if either type isvoid
. Converting a prvalue of type "pointer toT1
" to the type "pointer toT2
" (whereT1
andT2
are object types and where the alignment requirements ofT2
are no stricter than those ofT1
) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.
Given 3.9/9 both int8_t
and your enumeration type are standard layout types the question now transformed into:
*static_cast<int8_t*>(static_cast<void*>(&foo))
This is where you are out of luck. static_cast
is defined in 5.2.9 and there is nothing which makes the above legal - in fact 5.2.9/5 is a clear hint that it is illegal. The other clauses don't help:
- 5.2.9/13 requires
T*
->void*
->T*
whereT
must be identical (omitting cv) - 5.2.9/9 and 5.2.9/10 are not about pointers, but about values
- 5.2.9/11 is about classes and class hierarchies
- 5.2.9/12 is about class member pointers
My conclusion from this is that your code
reinterpret_cast<int8_t&>(foo)
is not legal, its behavior is not defined by the standard.
Also note that the above mentioned 5.2.9/9 and 5.2.9/10 are responsible for making the code legal which I gave in the initial answer and which you can still find at the top.
这篇关于是否可以将枚举类变量reinterpret_cast转换为基础类型的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!