是否可以将枚举类变量reinterpret_cast转换为基础类型的引用? [英] Is it safe to reinterpret_cast an enum class variable to a reference of the underlying type?

查看:238
本文介绍了是否可以将枚举类变量reinterpret_cast转换为基础类型的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我见过 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 类型的prvalue v 被转换为指向 cv T2 ,结果是 static_cast cv T2 *>(static_cast< cv T1 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 expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T 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 expression v. Conversions that can be performed explicitly using reinterpret_cast are listed below. No other conversion can be performed explicitly using reinterpret_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 to T2" if an expression of type "pointer to T1" can be explicitly converted to the type "pointer to T2" using a reinterpret_cast. The result refers to the same object as the source glvalue, but with the specified type. [ Note: That is, for lvalues, a reference cast reinterpret_cast<T&>(x) has the same effect as the conversion *reinterpret_cast<T*>(&x) with the built-in & and * operators (and similarly for reinterpret_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 to T1" is converted to the type "pointer to cv T2", the result is static_cast<cvT2*>(static_cast<cvvoid*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1, or if either type is void. Converting a prvalue of type "pointer to T1" to the type "pointer to T2" (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) 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* where T 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屋!

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