将enum类变量重新解释为基础类型的引用是否安全?

GOT*_*O 0 13 c++ reinterpret-cast c++11 enum-class

我已经看到过reinterpret_cast常用于对枚举类应用增量,我想知道这种用法在标准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))
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

我知道,如果是普通的类,那么转换为基类的引用是安全的.但由于枚举类不是隐式转换为其底层类型的事件,因此我不确定上述代码是否以及如何保证在所有编译器中都能正常工作.有线索吗?

Dan*_*rey 13

++如果你真的想迭代它的值,你可能想要为你的枚举重载运算符:

Foo& operator++( Foo& f )
{
    using UT = std::underlying_type< Foo >::type;
    f = static_cast< Foo >( static_cast< UT >( f ) + 1 );
    return f;
}
Run Code Online (Sandbox Code Playgroud)

并使用

for (Foo foo = Foo::First; foo != Foo::Last; ++foo)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

要回答是否reinterpret_cast允许的问题,一切都从5.2.10/1开始:

5.2.10重新解释强制转换[expr.reinterpret.cast]

1表达式reinterpret_cast<T>(v)的结果是将表达式转换v为type 的结果T.如果T是左值引用类型或函数类型的右值引用,则结果为左值; if T是对象类型的右值引用,结果是xvalue; 否则,结果是一个prvalue,并且对表达式执行左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换v.下面列出了可以使用显式执行的转换reinterpret_cast.无法使用明确执行其他转换reinterpret_cast.

(强调我的)

使用引用的重新解释基于5.2.10/11中的指针:

11如果类型"指向" 的表达式可以使用a 显式转换为"指向" 的类型,则T1可以将类型的glvalue表达式强制转换为"引用T2"类型.结果引用与源glvalue相同的对象,但具有指定的类型.[ 注意:也就是说,对于左值,参考演员与使用内置和运算符的转换具有相同的效果(同样适用于).- 结束注释 ]不创建临时,不进行复制,并且不调用构造函数(12.1)或转换函数(12.3).T1T2reinterpret_castreinterpret_cast<T&>(x)*reinterpret_cast<T*>(&x)&*reinterpret_cast<T&&>(x)

这改变了这个问题:

reinterpret_cast<int8_t&>(foo)
Run Code Online (Sandbox Code Playgroud)

这是否合法:

*reinterpret_cast<int8_t*>(&foo)
Run Code Online (Sandbox Code Playgroud)

下一站是5.2.10/7:

7可以将对象指针显式转换为不同类型的对象指针.当prvalue v类型的"指针T1"被转换为类型"指针CV T2 ",结果是如果两个和是标准布局类型(3.9)和的对准要求并不比那些更严格的,或者如果任一类型是.将"指向"的类型的prvalue转换为"指向"的类型(其中和是对象类型,并且对齐要求不比那些更严格)并返回其原始类型,产生原始指针值.未指定任何其他此类指针转换的结果.static_cast<cvT2*>(static_cast<cvvoid*>(v))T1T2T2T1voidT1T2T1T2T2T1

给定3.9/9两者int8_t并且您的枚举类型是标准布局类型,现在问题转换为:

*static_cast<int8_t*>(static_cast<void*>(&foo))
Run Code Online (Sandbox Code Playgroud)

这是你运气不好的地方.static_cast在5.2.9中定义并且没有任何理由使上述合法 - 事实上5.2.9/5明确暗示它是非法的.其他条款没有帮助:

  • 5.2.9/13要求T*- > void*- > T*哪里T必须相同(省略cv)
  • 5.2.9/9和5.2.9/10不是关于指针,而是关于值
  • 5.2.9/11是关于类和类层次结构的
  • 5.2.9/12是关于类成员指针的

我的结论就是你的代码

reinterpret_cast<int8_t&>(foo)
Run Code Online (Sandbox Code Playgroud)

不合法,其行为不是由标准定义的.

另请注意,上面提到的5.2.9/9和5.2.9/10负责使我在初始答案中给出的代码合法,并且您仍然可以在顶部找到.

  • +1'是否可以安全地重新解释为什么?' 经常是错误的"为什么我认为这是reinterpret_cast的用例?"的错误表述? (4认同)
  • @GOTO0 是的,它是一个对象。不,无作用域的枚举不是整数,它们仍然是(无作用域的)枚举。它们可以用于(提升)为整数,这是一种隐式转换,但这不会使它们成为本机整数。您需要区分类型系统及其规则以及内存位置及其内容。许多人从处理器的角度及其在内存中看到的内容进行思考,但是当编译器查看其内存位置表示的元信息时,这没有帮助。 (2认同)