Why can't I have an enum as the underlying typ

2019-02-26 07:30发布

问题:

Why isn't this valid C++?:

enum foo : unsigned { first_foo, second_foo };
enum bar : foo { best_foo = first_foo };

GCC 5.4.0 says:

/tmp/a.cpp:3:16: error: underlying type ‘foo’ of ‘bar’ must be an integral type
     enum bar : foo { best_foo = first_foo };

I can understand why I would get this error if foo were a float, or some struct, or what-not. But this seems perfectly legit to me in terms of semantics, type safety etc. What am I missing?

回答1:

When you add things to C++, you tend to add the minimium amount that solves a problem.

The enum A:int syntax lets you specify exactly how the enum A is stored as an integer. That is all it does, and it solves the problem.

enum A:B where B is an enum could have many meanings. A could extend B, or A could be a subset of the B underlying type with different names, or A could be an enum strictly restricted to have a subset of the values that can be stored within B, or A could be an enum whose values are restricted to the "hull" of B values.

Of these, the "same underlying type" solution (with the :int syntax) lines up with enum A:std::underlying_type_t<B>. So there is already a way to do that, and it isn't particularly burdensome.

Until someone makes a suggestion for what enum A:B should mean and convinces enough of the committee, it is unlikely to be permitted. And when there are multiple different reasonable meanings, this makes it harder for any one meaning to be chosen. One would need a strong use case why one particular meaning was best, and why it is worth the effort to put it in the standard.



回答2:

C++11 [dcl.enum]/2:

The type-specifier-seq of an enum-base shall name an integral type; any cv-qualification is ignored.

Enums are not themselves integral types – [basic.fundamental]/7:

Types bool, char, char16_t, char32_t, wchar_t, and the signed and unsigned integer types are collectively called integral types.

This is accompanied by a non-normative footnote:

Therefore, enumerations are not integral; however, enumerations can be promoted to integral types as specified in [conv.prom].

To achieve the effect I think you're looking for, however, is still simple:

enum bar : std::underlying_type<foo>::type { best_foo = first_foo };


回答3:

Well, not exactly the same, but I think you could use std::underlying_type:

enum foo : unsigned { first_foo, second_foo };
enum bar : std::underlying_type_t<foo> { best_foo = first_foo };


回答4:

For me it is a logical error to say a enum can be based on an another enum. If you think that the base is the storage type where the values defined in the enum are stored in, I can not get it as a logic expression to say the storage type is an enum. Because the enum is not only the storage type, it also contains a set of valid values.

If we can write something like:

enum A: int { ONE, TWO };

what should mean:

enum B: A{};

Because A defines not only the underlaying type ( I call this the storage type ) but also a set of valid values, should B only a subset of the enum A which means that you can define only values already defined in A?

Is it now valid to say we habe the values ONE,TWO already defined also in B? And is it now possible to add more values like:

    enum B: A{THREE};

and all valid values are now ONE,TWO,THREE ?

or is the meaning we get only the subset:

    enum B: A{ONE};

which means B can only use values already defined in A. Simply that makes it difficult to me to make a enum a base of another enum.

If you open that door, you also can also come to the idea that you want to use the underlaying storage type from other kinds of types like bitfields.

struct A { unsigned int a : 3; unsigned int B: 2; };

should then

enum B: A { ONE, TWO };

also be valid? I believe not! ;)

From the logical point ( my point of view ) the underlaying type of the enum is its storage type. And it makes no sense to make an enum as an underlaying storage type for another enum at all.