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?
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:
what should mean:
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:
and all valid values are now ONE,TWO,THREE ?
or is the meaning we get only the subset:
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.
should then
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.
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 theenum A
is stored as an integer. That is all it does, and it solves the problem.enum A:B
whereB
is an enum could have many meanings.A
could extendB
, orA
could be a subset of theB
underlying type with different names, orA
could be an enum strictly restricted to have a subset of the values that can be stored withinB
, orA
could be an enum whose values are restricted to the "hull" ofB
values.Of these, the "same underlying type" solution (with the
:int
syntax) lines up withenum 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.Well, not exactly the same, but I think you could use
std::underlying_type
:C++11 [dcl.enum]/2:
Enums are not themselves integral types – [basic.fundamental]/7:
This is accompanied by a non-normative footnote:
To achieve the effect I think you're looking for, however, is still simple: