简体   繁体   中英

why is the default type of enum class different than the underlying type of enum?

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.

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:

enum MyEnumType {
   Value1, Value2, Value3
 };

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:

enum MyEnumType2 {
   Value1, Value2, Value3, LastValue=0xffffff
 };

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:

 MyEnumType a = ...;
 fwrite(&a, sizeof(a), 1, fp);

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:

 enum class MyEnumType {
   ....
 }

defaults to type int. The underlying type can be explicitly changed by deriving your enum class from the appropriate numeric type.

For example:

 enum class MyEnumType : char {
   ....
 }

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.

As far as N4140 is concerned, MSVC is correct:

§7.2/5 Each enumeration defines a type that is different from all other types. Each enumeration also has an underlying type. The underlying type can be explicitly specified using an enum-base . For a scoped enumeration type, the underlying type is int if it is not explicitly specified. [...]

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:

§7.2/7 For an enumeration whose underlying type is not fixed, the underlying type is an integral type that can represent all the enumerator values defined in the enumeration. If no integral type can represent all the enumerator values, the enumeration is ill-formed. It is implementation-defined which integral type is used as the underlying type except that the underlying type shall not be larger than int unless the value of an enumerator cannot fit in an int or unsigned int . If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0 .

And N2347's proposed solutions:

This proposal is in two parts, following the EWG direction to date:

• provide a distinct new enum type having all the features that are considered desirable:

o enumerators are in the scope of their enum

o enumerators and enums do not implicitly convert to int

o enums have a defined underlying type

• provide pure backward-compatible extensions for plain enums with a subset of those features

o the ability to specify the underlying type

o the ability to qualify an enumerator with the name of the enum

The proposed syntax and wording for the distinct new enum type is based on the C++/CLI [C++/CLI] syntax for this feature. The proposed syntax for extensions to existing enums is designed for similarity.

So they went with the solution to give scoped enums a defined underlying type.

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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM