286

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?

JFMR
  • 23,265
  • 4
  • 52
  • 76
user1509260
  • 3,353
  • 3
  • 18
  • 9
  • 1
    [link](http://www.enel.ucalgary.ca/People/Norman/enel315_winter1997/enum_types/) Note that it doesn't matter whether the int matches one of the constants of the enum type; the type conversion is always illegal. – Labokas Mar 29 '14 at 11:39
  • 8
    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... – JohnRDOrazio Jan 24 '16 at 14:10

6 Answers6

334
int i = 1;
Test val = static_cast<Test>(i);
Andrew
  • 24,218
  • 13
  • 61
  • 90
  • 33
    auto val = static_cast(i); // C++11 – Mitch Sep 30 '16 at 17:58
  • 6
    @Mitch what do I get for using `auto` in this case? Is there any performance improvements? – Frederico Pantuzza May 19 '17 at 03:29
  • 9
    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. – avernus Dec 21 '19 at 14:35
  • 14
    @AydinÖzcan Modern IDEs can easily rename anything throughout your whole codebase. – Hugius Sep 16 '20 at 15:07
  • 2
    I would say the bigger improvement than ease of refactoring is mainly for things with long type signatures: `auto myptr = std::make_shared(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. – Will Eccles Apr 05 '21 at 13:26
84
Test e = static_cast<Test>(1);
bames53
  • 86,085
  • 15
  • 179
  • 244
  • MSDN: No run-time type check is made to help ensure the safety of the conversion (http://msdn.microsoft.com/en-us/library/c36yw7x9(v=vs.80).aspx). – Kirill Kobelev Jul 12 '12 at 13:43
  • 16
    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. – Kirill Kobelev Jul 12 '12 at 13:56
  • 2
    @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. – bames53 Jul 12 '12 at 17:09
  • 4
    what a conformant compiler should do, if enum has values { 1,3,5 } and code attempts to do from the value of 2. How will that differ from the C-cast? – Kirill Kobelev Jul 13 '12 at 00:23
  • 6
    @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. – bames53 Jul 13 '12 at 02:18
  • Thanks. This sounds much better than the prev message. – Kirill Kobelev Jul 13 '12 at 03:10
  • 4
    @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. – curiousguy Jul 15 '12 at 07:34
  • @curiousguy 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. – NoDataDumpNoContribution Aug 14 '17 at 11:27
31

Your code

enum Test
{
    A, B
}

int a = 1;

Solution

Test castEnum = static_cast<Test>(a);
jaques-sam
  • 2,578
  • 1
  • 26
  • 24
user1515687
  • 509
  • 3
  • 2
  • 50
    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. – Mike Seymour Jul 12 '12 at 13:57
  • 4
    @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??? – Kirill Kobelev Jul 13 '12 at 00:19
  • 7
    @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. – KillianDS Jul 13 '12 at 07:01
  • 5
    @KillianDS "_suppose you change a to another type later on_" which type? – curiousguy Jul 15 '12 at 07:14
  • @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`. – KillianDS Jul 15 '12 at 08:49
  • @KillianDS So, do you also use `static_cast`? What about `static_cast`? – curiousguy Jul 15 '12 at 21:56
  • 2
    Yes, either those or an implicit cast if available. It is much clearer to what the intent of the cast is. – KillianDS Jul 16 '12 at 05:28
  • 1
    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(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(a);` would have the desired result. Unless the result of Test::A is besides the point of the OP... – JohnRDOrazio Jan 24 '16 at 14:06
25

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);
Tommy
  • 99,986
  • 12
  • 185
  • 204
  • this solution worked in case compiler option blocked static_cast<> (semantic check). Not that it makes sense to me, but still neat. – Mr Buisson Nov 27 '19 at 12:29
  • 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. – Bill Hollings Mar 21 '21 at 18:28
  • 4
    @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. – rosshjb May 04 '21 at 12:02
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
Axel Krypton
  • 141
  • 3
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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
kosolapyj
  • 121
  • 1
  • 3