I am asking why the following code yields an error in Visual Studio 2014 update 4.
enum A
{ a = 0xFFFFFFFF };
enum class B
{ b = 0xFFFFFFFF };
I know that I can use enum class B : unsigned int
. But why is the default underlying type of enum
different that the default underlying type of enum class
? There should be a design decision.
Clarifications I forgot to mention the error:
error C3434: enumerator value '4294967295' cannot be represented as 'int', value is '-1'
That suggests that the default underlying type of enum class
is signed int
while the default type of enum
is unsigned int
. This question is about the sign part.
That's what the standard requires. A scoped enum always has an explicit underlying type, which defaults to
int
unless you say otherwise.As for the motivation: superficially, it doesn't make sense to conflate the underlying type with whether the enum is scoped or not. I suspect that this is done only because the authors want to always be able to forward declare scoped enums; at least in theory, the size and representation of a pointer to the enum may depend on the underlying type. (The standard calls such forward declarations opaque enum types.)
And no, I don't think this is really a valid reason for conflating scoping and underlying type. But I'm not the whole committee, and presumably, a majority don't feel the way I do about it. I can't see much use for specifying the underlying type unless you are forward declaring the enum; it doesn't help with anything else. Where as I want to use scoped enum pretty much everywhere I'm dealing with a real enumeration. (Of course, a real enumeration will never have values which won't fit in an
int
; those really only come up when you're using an enum to define bitmasks.)As far as N4140 is concerned, MSVC is correct:
For rationale, you can read the proposal entitled Strongly Typed Enums (Revision 3) N2347. Namely, section 2.2.2 Predictable/specifiable type (notably signedness) explains that the underlying type of
enum
is implementation-defined. For example, N4140 again:And N2347's proposed solutions:
So they went with the solution to give scoped enums a defined underlying type.
enum class is also called scoped enum.
enum is pretty much necessary for backwards compatibility reasons. scoped enum (or enum class) was added, among other reasons, to pin down the underlying type of the enum.
The details are as follows. When you do something like this:
The compiler is free to choose the underlying numeric type of MyEnumType as long as all your values can fit into that type. This means that the compiler is free to choose char, short, int, long, or another numeric type as the underlying type of MyEnumType. One practice that's done often is to add a last value to the enumeration to force a minimum size of the underlying type. For example:
is guaranteed to have an underlying type of at least as large as unsigned 32-bit, but it could be larger (for example, 64-bit unsigned). This flexibility on the compiler's part is good and bad.
It is good in that you don't have to think about the underlying type. It is bad in that this is now an uncertainty that is up to the compiler, and if you do think about the underlying type, you can't do anything about it. This means that the same piece of code can mean different things on different compilers, which may, for example, be a problem if you wanted to do something like this:
Where you're writing the enum to a file. In this case, switching compiler or adding a new value to the enumeration can cause the file to be misaligned.
The new scoped enumeration solves this issue, among other things. In order to do this, when you declare a scoped enum, there must be a way for the language to fix the underlying type. The standard is, then, that:
defaults to type int. The underlying type can be explicitly changed by deriving your enum class from the appropriate numeric type.
For example:
changes the underlying type to char.
For this reason, default underlying type of an enum can change based on how many items and what literal values are assigned to the items in the enumeration. On the other hand, the default underlying type of an enum class is always int.