For unknown reason I cannot initialize enum value from a constexpr
value. Here is my code:
enum class Enum: unsigned int; //Forward declaration
constexpr Enum constant = static_cast<Enum>(2);
enum class Enum: unsigned int {
A = 0,
B = 1,
C = B, //This works
D = constant, //This FAILS
E = static_cast<unsigned int>(constant), //This works
F = Enum::B //This works
};
What I cannot understand is why I can write C = B
, but cannot write D = constant
(B
and constant
have the same type!)
I still can do E = static_cast<unsigned int>(constant)
, but it is too verbose (in my real-life code each enum value is initialized by a constexpr
function call, and it is hard to put static_cast<unsigned int>
everywhere).
All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.
First of all, the enum type and its underlying type are not the same, and the enumerator of the former shall be defined with, if any, a constexpr value of the underlying type or a constant expression implicitly convertible to the underlying type.
As covered in the non-normative example of [dcl.enum]/10, there are no implicit conversions between a scoped enum and an integer, not even to its explicitly specified fixed underlying type:
and, as governed by the non-presence of scoped enumerations in the normative text of [conv.integral]/1 and [conv.prom]/4 ([conv.prom]/3 for unscoped enumerations types whose underlying type is not fixed) [emphasis mine]:
As such, your program, particularly the enumeration definition
D = constant
, is ill-formed.And indeed, if we modify your example such that
Enum
is changed into a non-scoped enumeration, the program is no longer ill-formed.Because of the somewhat tricky clause [dcl.enum]/5, which states that
In layman terms, the type of each enumerator basically changes depending on whether its viewed from within the definition of the enumeration or from outside of it.
This means that inside of the enum definition, we may use a previously defined enumerator in the definition of one that follows, as they both have the type (ignoring some details in [dcl.enum]/5.1 and [dcl.enum]/5.3 for enumerations where the underlying type is not fixed), no matter is the enum is scoped or not (i.e., no need for implicit conversions), whereas outside of the definition of the enum, these enumerators have the same type as that of the enum itself.