Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I have an enum as the underlying type of another enum?

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?

like image 622
einpoklum Avatar asked Nov 15 '16 10:11

einpoklum


People also ask

What is the underlying type of an enum?

The body of an enum type declaration defines zero or more enum members, which are the named constants of the enum type. No two enum members can have the same name. Each enum member has an associated constant value. The type of this value is the underlying type for the containing enum.

What is default underlying datatype of an enum?

A scoped enum always has an explicit underlying type, which defaults to int unless you say otherwise.

Can we have enum inside enum in C?

It is not possible to have enum of enums, but you could represent your data by having the type and cause separately either as part of a struct or allocating certain bits for each of the fields.

Can an enum extend another enum C++?

The Problem. C++ does not have a facility to allow one enum type to be extended by inheritance as it does for classes and structures. Sometimes it is important to have this functionality.


2 Answers

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 };
like image 107
ildjarn Avatar answered Sep 20 '22 23:09

ildjarn


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.

like image 35
Yakk - Adam Nevraumont Avatar answered Sep 21 '22 23:09

Yakk - Adam Nevraumont