如何在C++中将int转换为枚举类型?

292

如何在C++中将整数转换为枚举类型?

例如:

enum Test
{
    A, B
};

int a = 1;

我如何将a转换为类型Test::A


1
请注意,int类型是否与枚举类型的常量之一匹配并不重要;类型转换始终是非法的。 - Labokas
8
我认为,如果你想把 int a 转换成 Test::A,那么它的值必须为0,因为 Test::A 的隐含值为0,而 Test::B 的隐含值为1。除非特别强调要转换成 Test::A,否则这个事实可能并不重要。 - JohnRDOrazio
6个回答

338
int i = 1;
Test val = static_cast<Test>(i);

34
auto val = static_cast<Test>(i); // C++11自动推导类型的变量val,使用static_cast将i强制转换为Test类型。这是C++11中的语法。 - Mitch
6
在这种情况下,如果我使用auto,我会得到什么?是否有性能提升? - Frederico Pantuzza
9
没有性能改进。如果你用“auto”指定,编译器只是自动推断类型。如果你决定将来更改枚举名称,由于编译器会自动推断正确的类型名称,所以需要修改的代码较少。 - avernus
14
现代集成开发环境可以轻松地在整个代码库中更改任何名称。 - Hugius
2
我认为比重构容易更大的改进主要针对具有长类型签名的内容:auto myptr = std::make_shared<my::cool::type::class>(1, 2, 3, 4, 5); 比指定 myptr 的完整类型要短得多,而赋值语句的右侧清楚地说明了类型。 - Will Eccles

85
Test e = static_cast<Test>(1);

16
static_cast 运算符可以将整数类型的值显式转换为枚举类型。如果整数类型的值不在枚举值的范围内,则所得到的枚举值是未定义的。 - Kirill Kobelev
2
如果枚举类型的底层类型可以表示整数值,则生成的枚举必须具有该值。否则,产生的枚举值将是将表达式转换为枚举底层类型所得到的任何值。如果VC++做了不同的事情,那么我认为它是不符合标准的。 - bames53
4
一致的编译器应该如何处理,如果枚举有值{1,3,5},并且代码试图从值2进行<static_cast>转换。这与C-cast有什么不同? - Kirill Kobelev
6
@KirillKobelev 我不使用 static_cast 是因为它与 C 风格转换没有任何区别,我使用 static_cast 是因为 C++ 转换在风格上比 C 转换更可取。 - bames53
4
如果枚举类型具有值 {1,3,5},那么不行。枚举类型不能仅限于这3个可能的值:{1,3,5}是枚举器(命名的枚举值),而不是枚举本身。如果1、3、5是可能的枚举值,则2也是可能的枚举值。 - curiousguy
显示剩余3条评论

31

你的代码:

enum Test
{
    A, B
};

int a = 1;

解决方案:
Test castEnum = static_cast<Test>(a);

50
使用最严格的转换类型并尽量避免使用 C 风格转换,有助于编译器更好地检测错误。在这里,static_cast 将是更好的选择。 - Mike Seymour
4
@Mike Seymour,问题在于在这种情况下,静态转换与C转换没有区别。它如何检测错误以及什么错误可以检测出来? - Kirill Kobelev
7
问题在于 C 风格的强制类型转换不够明确。它可能等同于 static_cast,但也可能是一个 const_cast 或者更糟糕的是 reinterpret_cast,甚至是这些转换方式的组合。即使你现在知道它会退化成什么,但是假设你稍后将 a 更改为另一种类型,那么进行强制类型转换的方式也可能发生改变,而你甚至不会得到任何警告。这是你不想要的。 - KillianDS
5
“_suppose you change a to another type later on_” 指的是哪种类型? - curiousguy
2
是的,可以使用这些或者如果可用的话进行隐式转换。这样更清晰地表达了转换的意图。 - KillianDS
显示剩余3条评论

25
转化问题的结尾是“如何将a转换为类型Test::A”,而不是坚持要求在其中使用强制转换,由于这似乎是一个热门问题,而且没有人提到替代方案,根据C++11标准:

5.2.9 Static cast

... 表达式e可以使用形如static_cast<T>(e)static_cast显式转换为类型T,如果声明T t(e);对于某些虚构的临时变量t(8.5)是良好定义的。这种显式转换的效果与执行声明和初始化,然后使用临时变量作为转换结果相同。

因此,直接使用形式t(e)也可以工作,并且您可能会更喜欢它的整洁性:
auto result = Test(a);

这个解决方案在编译器选项阻止 static_cast<>(语义检查)的情况下有效。虽然我不太理解它的意义,但仍然很整洁。 - Mr Buisson
这里提供的解决方案对我有效,但我也很好奇为什么 Test result(a); 不起作用,因为它看起来是等价的。它会导致一个错误:“无法使用类型为'int'的lvalue初始化变量类型为'Test'”,而这似乎正是所提供的解决方案所做的。 - Bill Hollings
4
@BillHollings Test result(a); 看起来像是为类型 Test 创建一个名为 result 的变量的构造函数调用,并提供了参数 a。因为 Test 只是枚举类型,而不是类或结构体,所以你不能像构造函数一样调用它。但是 Test(a) 是一种类型转换,所以它们并不等价 — (Test)a 也可以工作。 - rosshjb

4

顺便提一下,如果C++17中枚举的基础类型是固定的,那么可以直接写

enum Test : int {A, B};
int a = 1;
Test val{a};

当然,Test val{1}; 也是有效的。

相关的cppreference部分如下(重点在于“underlying type fixed”):

如果以下所有条件都成立,则可以使用列表初始化从整数初始化枚举类型而无需强制转换:

  • 初始化为直接列表初始化
  • 初始化器列表只有一个元素
  • 枚举类型是作用域或非作用域的底层类型固定
  • 转换不是收窄的

1

Test castEnum = static_cast<Test>(a-1);将把a转换成A。如果您不想减去1,可以重新定义enum

enum Test
{
    A:1, B
};

在这种情况下,可以使用Test castEnum = static_cast<Test>(a);a转换为A

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接