You might want to overload operator ++
for your enum if you really want to iterate its values:
Foo& operator++( Foo& f )
{
using UT = std::underlying_type< Foo >::type;
f = static_cast< Foo >( static_cast< UT >( f ) + 1 );
return f;
}
and use
for (Foo foo = Foo::First; foo != Foo::Last; ++foo)
{
...
}
To answer the question of whether or not the reinterpret_cast
is allowed, it all starts with 5.2.10/1:
5.2.10 Reinterpret cast [expr.reinterpret.cast]
1 The result of the expression reinterpret_cast<T>(v)
is the result of converting the expression v
to type T
. If T
is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T
is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue and the lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the expression v
. Conversions that can be performed explicitly using reinterpret_cast
are listed below. No other conversion can be performed explicitly using reinterpret_cast
.
(emphasis mine)
The reinterpretation using references is based on pointers as per 5.2.10/11:
11 A glvalue expression of type T1
can be cast to the type “reference to T2
” if an expression of type “pointer to T1
” can be explicitly converted to the type “pointer to T2
” using a reinterpret_cast
. The result refers to the same object as the source glvalue, but with the specified type. [ Note: That is, for lvalues, a reference cast reinterpret_cast<T&>(x)
has the same effect as the conversion *reinterpret_cast<T*>(&x)
with the built-in &
and *
operators (and similarly for reinterpret_cast<T&&>(x)
). — end note ] No temporary is created, no copy is made, and constructors (12.1) or conversion functions (12.3) are not called.
Which transforms the question from this:
reinterpret_cast<int8_t&>(foo)
to whether this is legal:
*reinterpret_cast<int8_t*>(&foo)
Next stop is 5.2.10/7:
7 An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v
of type “pointer to T1
” is converted to the type “pointer to cv T2
”, the result is static_cast<
cv
T2*>(static_cast<
cv
void*>(v))
if both T1
and T2
are standard-layout types (3.9) and the alignment requirements of T2
are no stricter than those of T1
, or if either type is void
. Converting a prvalue of type “pointer to T1
” to the type “pointer to T2
” (where T1
and T2
are object types and where the alignment requirements of T2
are no stricter than those of T1
) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.
Given 3.9/9 both int8_t
and your enumeration type are standard layout types the question now transformed into:
*static_cast<int8_t*>(static_cast<void*>(&foo))
This is where you are out of luck. static_cast
is defined in 5.2.9 and there is nothing which makes the above legal - in fact 5.2.9/5 is a clear hint that it is illegal. The other clauses don't help:
- 5.2.9/13 requires
T*
-> void*
-> T*
where T
must be identical (omitting cv)
- 5.2.9/9 and 5.2.9/10 are not about pointers, but about values
- 5.2.9/11 is about classes and class hierarchies
- 5.2.9/12 is about class member pointers
My conclusion from this is that your code
reinterpret_cast<int8_t&>(foo)
is not legal, its behavior is not defined by the standard.
Also note that the above mentioned 5.2.9/9 and 5.2.9/10 are responsible for making the code legal which I gave in the initial answer and which you can still find at the top.