14

Why i can't use reinterpret_cast operator for such a cast?

enum Foo { bar, baz };

void foo(Foo)
{
}

int main()
{
   // foo(0); // error: invalid conversion from 'int' to 'Foo'
   // foo(reinterpret_cast<Foo>(0)); // error: invalid cast from type 'int' to type 'Foo'
   foo(static_cast<Foo>(0)); 
   foo((Foo)0);
}
4
  • 2
    static_cast is the correct operation here. Commented Sep 1, 2012 at 14:28
  • 1
    Why would it be valid? What do you think reinterpret_cast is for? Commented Sep 1, 2012 at 14:28
  • I think that reinterpret_cast can be use for all types of casts, because it's force any type casts to another type with all side-effects of this conversion. Commented Sep 1, 2012 at 14:30
  • 1
    Here's a good explanation: stackoverflow.com/questions/573294/when-to-use-reinterpret-cast Commented Sep 1, 2012 at 14:31

4 Answers 4

24

I think that reinterpret_cast can be use for all types of casts, because it's force any type casts to another type with all side-effects of this conversion.

That is a common misconception. Conversions which can be performed with reinterpret_cast are listed explicitly in 5.2.10 of the standard. int-to-enum and enum-to-int conversions are not in the list:

  • Pointer to integral type, so long as the integer is large enough to hold it
  • nullptr_t to integer
  • integral type or enum to pointer
  • function pointer to another function pointer of different type
  • object pointer to another object pointer of different type
  • nullptr_t to other pointer type
  • pointer-to-member of T1 to a different pointer-to-member of T2 in cases where both T1 and T2 are objects or functions

reinterpret_cast is typically used to tell the compiler: Hey, I know you think this region of memory is a T, but I'd like you to interpret it as a U (where T and U are unrelated types).

It is also worth noting that reinterpret_cast can have effects on the bits:

5.2.10.3

[ Note: The mapping performed by reinterpret_cast might, or might not, produce a representation dif- ferent from the original value. — end note ]

The C-style cast always works, because it included static_cast in its attempts.

Sign up to request clarification or add additional context in comments.

Comments

4

Because regular enum underlying type is int, there is nothing to reinterpret. Static cast is proper conversion for this case.

9 Comments

@Rost that is not true. The standard guarantees that an emum's underlying type is an integral type, but not necessarily an int.
@tenfour Well, it was added in C++11. Don't know the reason. Possibly to allow some template tricks?
If "there is nothing to reinterpret" had anything to do with correctness, then this would fail: int x = 0; int* p = reinterpret_cast<int*>(&x);
@TravisGockel Even reinterpret_cast<int>(x) is allowed. So what? It just means that reinterpret_cast don't actually reinterpret in some cases. So, shall we name it maybe_reinterpret_cast? ;-)
The reason enum-to-int can't be done through reinterpret_cast has nothing to do with the underlying type of the enum. If it was enum Foo : uint64_t { bar, baz }, reinterpret_cast<int> still wouldn't be allowed.
0

Other answers fail to get to the point directly. Despite being a bad use of reinterpret_cast, compilation fails because you can't apply reinterpret_cast on values directly. You can apply it only to convert pointers of reference expressions. (in particular, it can't convert literal constants.)

So this compiles,

enum Foo { bar, baz };

void foo(Foo)
{
}

int main()
{
   // foo(0);
   int zero = 0;
   foo(reinterpret_cast<Foo&>(zero)); // error: invalid cast from type 'int' to type 'Foo'
   foo(static_cast<Foo>(0)); 
   foo((Foo)0);
}

https://godbolt.org/z/x6MP1e5eo

Comments

0

reinterpret_cast is used only for pointers, to be able to convert between the address and an integral type, or between two otherwise incompatible pointer types.

However, if you absolutely wish to use reinterpret_cast for enums, you can! You can do reinterpret_cast<Foo&>(value) or, in this case reinterpret_cast<const Foo&>(static_cast<const std::underlying_type_t<Foo>&>(0)). This is a well-defined operation, resulting in *reinterpret_cast<Foo*>(&value). This works because std::underlying_type_t<Foo> is either signed or unsigned type corresponding to Foo and thus accessible through the pointer.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.