[dcl.enum]/8:
For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type.
All enum class
have a fixed underlying type; either explicit, or int if not given explicitly.
So they are guaranteed to be able to store anything their underlying type can.
Unscoped enums (enum
without class
or struct
) have different rules; their valid values are basically the 2s complement binary cube of the enumerator values. If your enum was unscoped, setting its value to 3 wouldn't be portable.
I suspect this rule for scoped enums was done in order to make it easier to check correctness in some sense; they are guaranteed to be some integral type. Checking correctness of unscoped enum use was hard. It does mean you cannot as a programmer assume enums are only in the state of their enumerated values; but ensuring that would both ruin lots of use cases for enum and be difficult to guarantee practically.
You could probably make a proposal for a strict enum, which can only be in the named states, if you see a huge advantage from it.
For non-scoped enums: [dcl.enum] 7.2/8
For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the
underlying type. Otherwise, for an enumeration where
e_min
is the smallest enumerator and
e_max
is the
largest, the values of the enumeration are the values in the range
b_min
to
b_max
, defined as follows: Let
K
be 1 for a two’s complement representation and 0 for a one’s complement or sign-magnitude representation.
b_max
is the smallest value greater than or equal to
max
(
|
e_min
|−
K,
|
e_max
|
)
and equal to
2^M
−
1
, where
M
is a non-negative integer.
b_min
is zero if
e_min
is non-negative and
−
(
b_max
+
K
)
otherwise. The size of
the smallest bit-field large enough to hold all the values of the enumeration type is
max
(
M,
1)
if
b_min
is
zero and
M
+ 1
otherwise. It is possible to define an enumeration that has values not defined by any of its
enumerators. If the
enumerator-list
is empty, the values of the enumeration are as if the enumeration had a
single enumerator with value 0
[expr.static.cast] 5.2.8/10:
A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is
unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the resulting
value is unspecified (and might not be in that range).
converting to a non-scoped enum outside the binary closure of the values of the enum results in an unspecified value, even if it fits in the underlying type.
enum foo{zero, one};
the underlying type of foo
is going to be some integral type, and foo
is layout-compatible with that integral type, and that integral type may hold 2
just file, but converting 2 to foo
results in foo
storing an unspecified value.