What happens if an enum cannot fit into an unsigned integral type?

This is a very interesting question. The simple answer is that this is literally undefined: the standard doesn’t say anything about this case.

To have a better example, consider this enum:

 enum foo : bool { True=true, undefined };

According to the standard:

[dcl.enum]/2: […] An enumerator-definition without an initializer gives the enumerator the value obtained by increasing the value of the previous enumerator by one.

Therefore, the value of foo::undefined in our example is 2 (true+1). Which can not be represented as a bool.

Is it ill-formed?

No, according to the standard, it is perfectly valid, only not-fixed underlying type have a restriction about not being able to represent all of the enumerator values:

[dcl.enum]/7: For an enumeration whose underlying type is not fixed, […] If no integral type can represent all the enumerator values, the enumeration is ill-formed.

It says nothing about a fixed underlying type that can not represent all the enumerator values.

What is the value of original question’s oops and undefined?

It is undefined: the standard doesn’t say anything about this case.

Possible values for foo::undefined:

  • Highest possible value (true): undefined and oops should be underlying type‘s maximum value.
  • Lowest possible value (false): the underlying type‘s minimum value. Note: In signed integers, it would not match the current behavior for Integer overflow (undefined behavior).
  • Random value (?): the compiler will choose an value.

The problem with all of these values is that it may result two fields with the same value (e.g. foo::True == foo::undefined).

The difference between initializer (e.g. undefined=2) and “implicit” initializer (e.g. True=true, undefined)

According to the standard:

[dcl.enum]/5: If the underlying type is fixed, the type of each enumerator prior to the closing brace is the underlying type and the constant-expression in the enumerator-definition shall be a converted constant expression of the underlying type.

In other words:

 enum bar : bool { undefined=2 };

is equivalent to

 enum bar : bool { undefined=static_cast<bool>(2) };

And then bar::undefined will be true. In an “implicit” initializer, it would not be the case: this standard paragraph say it about only initializer, and not about “implicit” initializer.

Summary

  1. With this way, it is possible for an enum with a fixed-underlying-type to have unrepresentable values.
  2. Their value is undefined by the standard.

According to the question and comments, this is not valid in GCC and clang but valid for MSVS-2015 (with a warning).

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)