How to cast int to enum in C++?
Asked Answered
J

6

300

How do I cast an int to an enum in C++?

For example:

enum Test
{
    A, B
};

int a = 1;

How do I convert a to type Test::A?

Jesse answered 12/7, 2012 at 13:30 Comment(2)
link Note that it doesn't matter whether the int matches one of the constants of the enum type; the type conversion is always illegal.Porch
I believe that if you want to cast to Test::A the value of int a will have to be 0, because Test::A has an implicit value of 0 and Test::B has an implicit value of 1. Unless the fact of casting specifically to Test::A is besides the point...Orchitis
R
346
int i = 1;
Test val = static_cast<Test>(i);
Reprobative answered 12/7, 2012 at 13:33 Comment(6)
auto val = static_cast<Test>(i); // C++11Uitlander
@Uitlander what do I get for using auto in this case? Is there any performance improvements?Caldwell
No performance improvements. Compiler just deduces the type automatically if you specify with "auto". If you decide to change your enum name in the future, you will be modifying your code less since compiler will automatically deduce the correct type name.Masseuse
@AydinÖzcan Modern IDEs can easily rename anything throughout your whole codebase.Baccarat
I would say the bigger improvement than ease of refactoring is mainly for things with long type signatures: auto myptr = std::make_shared<my::cool::type::class>(1, 2, 3, 4, 5); is much shorter than specifying the full type of myptr, and the right-hand side of the assignment makes it clear what the type is anyway.Cecillececily
What happens if i is out of range of the enum definitions?Nunatak
A
86
Test e = static_cast<Test>(1);
Alpaca answered 12/7, 2012 at 13:33 Comment(8)
MSDN: No run-time type check is made to help ensure the safety of the conversion (msdn.microsoft.com/en-us/library/c36yw7x9(v=vs.80).aspx).Qnp
MSDN: The static_cast operator can explicitly convert an integral value to an enumeration type. If the value of the integral type does not fall within the range of enumeration values, the resulting enumeration value is undefined.Qnp
@KirillKobelev if the integral value can be represented by the underlying type of the enum then the resulting enum must have that value. Otherwise the produced enum value will be whatever value results from converting the expression to the enum's underlying type. If VC++ does something different then I think it's non-conformant.Alpaca
what a conformant compiler should do, if enum has values { 1,3,5 } and code attempts to do <static_cast> from the value of 2. How will that differ from the C-cast?Qnp
@KirillKobelev I'm not using a static_cast because it does anything different from a C style cast, I'm using static_cast because C++ casts are stylistically preferable to C casts.Alpaca
Thanks. This sounds much better than the prev message.Qnp
@KirillKobelev "if enum has values { 1,3,5 }" No. The enumeration type cannot be limited to only these 3 possible values: { 1,3,5 } are the enumerators (named enumeration values), not the enumeration itself. If 1,3,5 are possible enumeration values, then so is 2.Kerosene
@Kerosene Actually very important point. See the linked duplicate question for explicitly handling this case while this question here and all top answers here leaves this open.Invincible
H
32

Your code:

enum Test
{
    A, B
};

int a = 1;

Solution:

Test castEnum = static_cast<Test>(a);
Heilner answered 12/7, 2012 at 13:48 Comment(9)
It's a good idea to use the most restrictive cast you can, and avoid C-style casts altogether, to give the compiler it's best chance at detecting mistakes. static_cast would be a better cast here.Tiresome
@Mike Seymour, the problem is that static cast has no difference from the C-cast in this case. How and what mistake it can detect???Qnp
@KirillKobelev: The problem is that a C-style cast is not explicit. It can be equal to a static_cast, but it could as well be a const_cast or even worse, a reinterpret_cast or even a combination of those. Even if you know now in what it will degrade, suppose you change a to another type later on, it could very well be the type of casting changes without you ever getting as much as a warning, you don't want that.Masticate
@Masticate "suppose you change a to another type later on" which type?Kerosene
@curiousguy: in general, it does not matter. for enums all native types will result in a static_cast, but for casting to another type it may change to a reinterpret_cast. It is good practice to use the same types of casts everywhere in your code, so you shouldn't suddenly use C-style casts for enums.Masticate
@Masticate So, do you also use static_cast<float>? What about static_cast<string>?Kerosene
Yes, either those or an implicit cast if available. It is much clearer to what the intent of the cast is.Masticate
in the given case, wouldn't Test::A have an implicit value of 0, and Test::B an implicit value of 1? so Test castEnum = static_cast<Test>(a); would actually result in castEnum == Test::B? I believe if you want to cast to Test::A, the value to cast will have to be 0, so: enum Test { A, B } int a = 0; Test castEnum = static_cast<Test>(a); would have the desired result. Unless the result of Test::A is besides the point of the OP...Orchitis
@Masticate you know, reinterpret cast only works on pointers or references. And all this named cast is bull when Cpp implicitly does Copy and Move semantics. Me dont use named cast unless I specifically want something. Like that's too much typing for nothing.Clorindaclorinde
F
27

Spinning off the closing question, "how do I convert a to type Test::A" rather than being rigid about the requirement to have a cast in there, and answering several years late only because this seems to be a popular question and nobody else has mentioned the alternative, per the C++11 standard:

5.2.9 Static cast

... an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion.

Therefore directly using the form t(e) will also work, and you might prefer it for neatness:

auto result = Test(a);
Footless answered 15/8, 2019 at 21:27 Comment(3)
this solution worked in case compiler option blocked static_cast<> (semantic check). Not that it makes sense to me, but still neat.Etra
The solution provided here works for me, but I'm also curious as to why Test result(a); does NOT work, when it seems equivalent. It results in an error "Cannot initialize a variable of type 'Test' with an lvalue of type 'int'", where this seems to be exactly what the provided solution does too.Jurkoic
@BillHollings Test result(a); looks like a constructor call for type Test with variable result, providing an arugment a. Because Test is just enumerated type, not a class or struct, you can't call it like constructor. But the Test(a) is a type conversion, so they are not equivalent — (Test)a also works.Detinue
S
4

Just to mention it, if the underlying type of the enum happens to be fixed, from C++17 on, it is possible to simply write

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

and, of course, Test val{1}; is also valid.

The relevant cppreference part reads (emphasis mine):

An enumeration can be initialized from an integer without a cast, using list initialization, if all of the following are true:

  • the initialization is direct-list-initialization
  • the initializer list has only a single element
  • the enumeration is either scoped or unscoped with underlying type fixed
  • the conversion is non-narrowing
Sinclare answered 15/6, 2022 at 15:40 Comment(0)
N
1

Test castEnum = static_cast<Test>(a-1); will cast a to A. If you don't want to substruct 1, you can redefine the enum:

enum Test
{
    A:1, B
};

In this case Test castEnum = static_cast<Test>(a); could be used to cast a to A.

Neurology answered 16/8, 2019 at 14:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.