As requested by Bathsheba and as a follow up question to "What happens if an enum cannot fit into an integral type?":
Asuming an enum is defined as follows :
enum foo : unsigned int { bar = UINT_MAX, oops };
Is the value of oops
defined or isn't it?
MSVS2015 compilation:
warning C4340: 'oops': value wrapped from positive to negative value warning C4309: 'initializing': truncation of constant value warning C4369: 'oops': enumerator value '4294967296' cannot be represented as 'unsigned int', value is '0'
MSVS2015 output:
bar = 4294967295 oops= 0
gcc 4.9.2 compilation:
9 : note: in expansion of macro 'UINT_MAX' bar = UINT_MAX, ^ 10 : error: enumerator value 4294967296l is outside the range of underlying type 'unsigned int' oops ^ Compilation failed
gcc 4.9.2 output
//compilation failed
An enum type is represented by an underlying integer type. The size of the integer type and whether it is signed is based on the range of values of the enumerated constants. In strict C89 or C99 mode, the compiler allows only enumeration constants with values that will fit in "int" or "unsigned int" (32 bits).
An enumeration is a user-defined type that consists of a set of named integral constants that are known as enumerators. This article covers the ISO Standard C++ Language enum type and the scoped (or strongly-typed) enum class type which is introduced in C++11.
Enumerations are integers, except when they're not - Embedded.com.
An enum can, just like a class , have attributes and methods. The only difference is that enum constants are public , static and final (unchangeable - cannot be overridden).
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
.
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.
oops
and undefined
?It is undefined: the standard doesn't say anything about this case.
Possible values for foo::undefined
:
true
): undefined
and oops
should be underlying type's maximum value.false
): the underlying type's minimum value. Note: In signed integers, it would not match the current behavior for Integer overflow (undefined behavior).The problem with all of these values is that it may result two fields with the same value (e.g. foo::True == foo::undefined
).
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.
enum
with a fixed-underlying-type to have unrepresentable values.According to the question and comments, this is not valid in GCC and clang but valid for MSVS-2015 (with a warning).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With