将枚举类变量重新解释为基础类型的引用是否安全? 我见过代码> RealTytCase< /Cuff>用于将增量应用于枚举类,并且我想知道在标准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)) { ... } enum类Foo:int8\t { Bar1, Bar2, Bar3, Bar4, 第一个=Bar1, 最后=巴4 }; 对于(Foo-Foo=Foo::First;Foo

将枚举类变量重新解释为基础类型的引用是否安全? 我见过代码> RealTytCase< /Cuff>用于将增量应用于枚举类,并且我想知道在标准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)) { ... } enum类Foo:int8\t { Bar1, Bar2, Bar3, Bar4, 第一个=Bar1, 最后=巴4 }; 对于(Foo-Foo=Foo::First;Foo,c++,c++11,reinterpret-cast,enum-class,C++,C++11,Reinterpret Cast,Enum Class,来说,只要强制转换为枚举的确切底层类型,它就是安全的 如果枚举类的基础类型发生更改,++reinterpret\u cast(foo)会自动中断 更安全的版本: foo = static_cast<Foo>(static_cast<std::underlying_type<Foo>::type>(foo) + 1); foo=static\u cast(static\u cast(foo)+1); 或者 ++reinterpret_cast(foo); 如

来说,只要强制转换为枚举的确切底层类型,它就是安全的

如果枚举类的基础类型发生更改,
++reinterpret\u cast(foo)
会自动中断

更安全的版本:

foo = static_cast<Foo>(static_cast<std::underlying_type<Foo>::type>(foo) + 1);
foo=static\u cast(static\u cast(foo)+1);
或者

++reinterpret_cast(foo);

如果确实要迭代枚举的值,可能需要为枚举重载运算符
++

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

要回答是否允许重新解释演员阵容的问题,请从5.2.10/1开始:

5.2.10重新解释铸件[解释铸件] 1表达式
的结果重新解释(v)
是将表达式
v
转换为类型
T
的结果。如果
T
是一个左值引用类型或一个右值引用到函数类型,则结果为左值;如果
T
是一个右值引用到对象类型,则结果为x值;否则,结果为PR值,左值到右值(4.1)在表达式
v
上执行数组到指针(4.2)和函数到指针(4.3)的标准转换,下面列出了可以使用
reinterpret\u cast
显式执行的转换。不能使用
reinterpret\u cast显式执行其他转换

(强调矿山)

根据5.2.10/11,使用参考重新解释基于指针:

11如果“指向
T1
的指针”类型的表达式可以显式转换为“指向
T2
的指针”类型,则可以将
T1
类型的glvalue表达式转换为“指向
T2
的指针”类型使用
reinterpret\u cast
。结果引用与源glvalue相同的对象,但具有指定的类型。[注意:即,对于左值,引用cast
reinterpret\u cast(x)
与使用内置
&
*
运算符的转换
*reinterpret\u cast(&x)
具有相同的效果(同样对于
重新解释(x)
)-结束注释]不创建临时文件,不制作副本,也不调用构造函数(12.1)或转换函数(12.3)

这将问题转化为:

reinterpret_cast<int8_t&>(foo)
这就是你运气不好的地方。
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)
reinterpret\u cast(foo)
是不合法的,它的行为没有标准的定义


还请注意,上述5.2.9/9和5.2.9/10负责使代码合法化,我在初始答案中给出了代码,您仍然可以在顶部找到代码。

增量通过不同类型的左值访问
foo
,这是未定义的行为,3.10中列出的情况除外[basic.lval]。枚举类型及其基础类型不在该列表中,因此代码具有未定义的行为

对于一些支持非标准扩展的编译器,您可以通过类型双关来实现:

union intenum
{
    int8_t i;
    Foo    e;
};

intenum ie;
for (ie.e = Foo::First; ie.e <= Foo::Last; ++ie.i)
  // ...
这是便携式和安全的


(IMHO仍然不是一个好主意,因为可能有多个枚举数具有相同的值,或者枚举类型的值没有相应的枚举数标签。)

如果Bar1=10和Bar4=1会发生什么?-这不是你问题的答案,只是一个相关的问题。@Skeen你不使用上述模式,在这种情况下,
首先
最后
。还有
静态_cast
有什么问题吗?我确实相信,对于重新解释的casted值,你能做的唯一非UD的事情就是强制转换返回!@Skeen static_cast在强制转换到引用时不能使用,至少VC11不允许。因为这里没有任何枚举数被显式设置为值,所以我认为不能保证它们会被排序,编译器可以自由设置Bar1=10和Bar4=1,如果它想我相信这会在底层类型中断时发生大于
int
@nightcracker它确实存在。您可以使用
static_-cast(static_-cast(foo)+1)
。但是它确实需要C++11。@nightcracker感谢
std::底层_-type
,不知道它的存在。或者一个辅助函数:
模板T inc_-enum(tx){返回static_-cast(static_-cast(x)+1)}
操作符+++
不会改变它的参数,所以
++foo
不会改变
foo
+1“重新解释什么都安全吗?”经常是错误的表述“我为什么认为这是重新解释的用例?”谢谢@Daniel,我感谢你的研究努力。这不会改变根据你的结论,但是
&foo
真的是一个对象指针吗?看看规范,我不确定…@GOTO0
&foo
是指向你的枚举(它是一个对象)的指针,例如,
foo*
。或者我误解了你的问题吗?@GOTO0是的,它是一个对象。不,未范围的枚举不是整数,它们仍然是(未范围的)枚举。它们可以使用(升级)为整数,这是一种隐式转换,但这不会使它们成为本机整数。您需要区分
*reinterpret_cast<int8_t*>(&foo)
*static_cast<int8_t*>(static_cast<void*>(&foo))
reinterpret_cast<int8_t&>(foo)
union intenum
{
    int8_t i;
    Foo    e;
};

intenum ie;
for (ie.e = Foo::First; ie.e <= Foo::Last; ++ie.i)
  // ...
for (int8_t i = static_cast<int8_t>(Foo::First);
     i <= static_cast<int8_t>(Foo::Last);
     ++i)
{
  Foo e = static_cast<Foo>(i);
  // ...
}