Date: Mon, 27 Apr 2026 23:44:35 +0200
Hi all!
I am a bit late to the discussion. I don't understand the metaprogramming
stuff, but I read the original mail and have some thought. I hope they are
relevant.
I think simple things should be simple to do.
I also think that there's enough things going on with the scoped enum
declaration syntax that any newly added syntax is just odd, at least the
examples I have seen.
I also agree with the thoughts that
- it's difficult to choose a way to continue the enumeration values, and
probably the best option is to continue where the base enum's author
intended it
- multiple enum inheritance is maybe too much to ask for.
With all of these in mind, here's a possible extension using new attributes:
enum class Base {
a,
b,
c
} [[extendable(c+1)]];
enum class Derived [[extends(Base)]] {
d, // = c+1
e
};
This very clearly indicates the intention that we want to be able to extend
the base enum.
This syntax is pretty self-explanatory IMO.
The author of the base enum has control over the suggested starting value
of the derived enum. This makes it easy to define bitflags as well:
enum class Base : uint32_t {
a = 0x1,
b = a << 1,
c = a << 2
} [[extendable(a << 3)]];
enum class Derived [[extends(Base)]] {
d,
e = d << 1
};
Just my two cents.
Sincerely,
Matthew
Robin Savonen Söderholm via Std-Proposals <std-proposals_at_[hidden]>
ezt írta (időpont: 2026. ápr. 27., Hét 20:51):
> Just a thought: we might be able to implement this with library features
> as well using reflections. The problem is that we have quite a few knobs to
> turn that makes it less thsn ideal to standardise, but makes it the more
> convenient for users to tailor their own versions. A pseudocode prototype
> as a library implementation could be something like:
> ```
> enum class the_base_enum {
> value_a = 0,
> value_b = 1
> };
>
> enum class some_enum_extensions {
> value_c = 2
> };
>
> using enum_with_extensions = enum_union<the_base_class,
> some_enum_extensions>;
> ```
>
> The user can in this case decide how the "union" should behave. Maybe the
> various enums should have unique values, which means that the type can just
> keep a "std::common_type_t<std::underlying_t<Enums>...>" as a member and
> have a "static_assert" that the members from each enum does not compete for
> the same representation value (or not, if the enums actually do have
> members that are supposed to mean the same thing). Or it could act more
> like a "std:: variant", effectively keeping two indices and acts as a "meta
> enum".
> The user could also potentially (unsure if current version of reflections
> allow it but that could be extended) expose all members from each enum as a
> member in the class template instantiation. I. e. meaning that if we
> continue from the code above, the implementation could provide the ability
> to do:
> ```
> auto my_value = enum_with_extensions::value_c;
> ```
>
> But I personally see a bit too many trade offs without a clear cut "most
> likely optimal in most cases" path to take to really push for it. And
> similar trade offs are seen in the compiler extension version as well.
>
> Anyhow, just my thoughts.
>
> Good evening,
> Robin
>
> On Sat, Apr 25, 2026, 10:22 Sebastian Wittmeier via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> I was only concentrating on the combination, as the metaclasses were
>> discussed.
>>
>>
>>
>> For convertibility of pointers along the inheritance chain, the Base
>> pointer itself (probably not the object instance) has to keep the actual
>> type.
>>
>>
>>
>> Or one leaves out pointer convertibility. Enums are a simple value type.
>> We can't convert between int* and float* either. But we can assign values
>> between them. Or create a std::variant. Such features can be useful for
>> enums.
>>
>>
>> -----Ursprüngliche Nachricht-----
>> *Von:* Jens Maurer <jens.maurer_at_[hidden]>
>> *Gesendet:* Sa 25.04.2026 10:03
>> *Betreff:* Re: [std-proposals] Add inheritance for Enum Class
>> enumerations
>> *An:* std-proposals_at_[hidden];
>> *CC:* Sebastian Wittmeier <wittmeier_at_[hidden]>;
>>
>>
>> On 4/25/26 01:11, Sebastian Wittmeier via Std-Proposals wrote:
>> > They could have different underlying representations:
>>
>> Yes.
>>
>> > With strong typing the compiler could add an offset for one of the
>> ancestor enum classes.
>>
>> No, that won't work.
>>
>>
>> If this hypothetical feature is just for re-using enum values
>> and allowing conversion from a "base" value to a "derived" enum type,
>> then maybe there's some merit hidden here. However, I can't see how
>> to make a "Derived*" convert to a "Base*", similar to class derivation.
>>
>>
>> Alternative syntax suggestion:
>>
>> enum class Derived {
>> using enum Base; // import the enumerators here; ugh, semicolon
>> NEXT_ENUM = whatever,
>> };
>>
>> Jens
>>
>>
>> >
>> > -----Ursprüngliche Nachricht-----
>> > *Von:* Arthur O‘Dwyer via Std-Proposals <
>> std-proposals_at_[hidden]>
>> > *Gesendet:* Fr 24.04.2026 23:10
>> > *Betreff:* Re: [std-proposals] Add inheritance for Enum Class
>> enumerations
>> > *An:* std-proposals_at_[hidden];
>> > *CC:* Arthur O‘Dwyer <arthur.j.odwyer_at_[hidden]>;
>> > On Fri, Apr 24, 2026 at 4:00 PM Gašper Ažman via Std-Proposals <
>> std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]>>
>> wrote:
>> >
>> > Note that `using enum` exists and probably does what you need.
>> >
>> >
>> > I don't think "using enum" does what Andrey wants — because I think
>> Andrey is trying to describe this other common problem instead. This
>> /r/ProgrammingLanguages thread <
>> https://www.reddit.com/r/ProgrammingLanguages/comments/rk1y4u/extending_enums/>
>> calls it "extending enums."
>> > Here's some lightly-anonymized code from a real (DNS-related)
>> codebase:
>> >
>> > enum HttpServerStat {
>> > TLS_HANDSHAKES,
>> > TLS_HANDSHAKE_ERRORS,
>> > TLS_HANDSHAKE_TIMEOUTS,
>> > [...]
>> > RESPONSE_DROPS,
>> > MAX_HTTP_SERVER_STAT_ID
>> > };
>> >
>> > enum HttpStat {
>> > // Extends HttpServerStat
>> > QUERY_COUNT_HTTP = MAX_HTTP_SERVER_STAT_ID,
>> > QUERY_BYTES_HTTP,
>> > RESPONSE_COUNT_HTTP,
>> > RESPONSE_BYTES_HTTP,
>> > [...]
>> > MAX_HTTP_STAT_ID
>> > };
>> >
>> > enum ODoHStat {
>> > // Extends HttpStat
>> > ODOH_QUERY_COUNT = MAX_HTTP_STAT_ID,
>> > ODOH_QUERY_BYTES,
>> > [...]
>> > ODOH_4XX_RESPONSE,
>> > MAX_ODOH_STAT_ID
>> > };
>> >
>> > (Sidebar: We had to make some very minor changes to the users of
>> this code for C++20, which tightened restrictions on cross-enum arithmetic
>> and comparison.)
>> > The idea is that ODoHStat "extends" HttpStat in the same way that
>> std::partial_ordering "extends" std::strong_ordering. Every value in the
>> domain of HttpStat is also in the domain of ODoHStat (although the reverse
>> is not true).
>> > Notice that this is the opposite of what class inheritance means!
>> When a /class/ ODoHStat /derives/ from HttpStat then we say that every
>> object of type ODoHStat is an object of type HttpStat (not the reverse).
>> >
>> > What we really want to be able to say here is something like
>> > enum class ODoHStat : using HttpStat {
>> > ODOH_QUERY_COUNT = MAX_HTTP_STAT_ID,
>> > ODOH_QUERY_BYTES,
>> > [...]
>> > ODOH_4XX_RESPONSE,
>> > MAX_ODOH_STAT_ID
>> > };
>> > Again, notice the inappropriateness of "inheritance" syntax here.
>> > enum ODoHStat : HttpStat { // NO!
>> > Because that syntax already has a meaning for enum declarations:
>> it's "HttpStat is the underlying type of ODoHStat; we guarantee that all
>> values of type ODoHStat will fit into an HttpStat." Which is /*not at all*/
>> what we mean here; in fact we mean the opposite: here we guarantee that all
>> values of type /HttpStat/ will fit into an /ODoHStat/.
>> >
>> > This fantasy feature would permit us to use `enum class`, and
>> expose all the enumerators of the "parent" enum as members of the "child",
>> thus:
>> > ODoHStat e = ODoHStat::QUERY_COUNT_HTTP;
>> > Today, we can't do that. We can either avoid scoped enums
>> altogether, or else we have to write
>> > ODoHStat e = static_cast<ODoHStat>(HttpStat::QUERY_COUNT_HTTP);
>> >
>> > If we got such a facility:
>> >
>> > (1) We would not want to permit the "child" enum to just start
>> listing new enumerators without an initializer for the first one:
>> > enum class ODoHStat : using HttpStat { ODOH_QUERY_COUNT,
>> ODOH_QUERY_BYTES, [...] // NO!
>> > because what would they start numbering at — zero?
>> one-more-than-the-parent-enum's-highest-enumerator?
>> std::bit_ceil-of-one-more-than-the-parent-enum's-highest-enumerator? None
>> of these are safe answers. The only safe pattern is as we do in the code
>> above: start where the parent enum tells you to start. Even then, this is
>> super fragile: if we add a new enumerator to HttpStat, that will increment
>> the values of ODoHStat's enumerators too. Arguably the author of ODoHStat
>> knew what they were signing up for when they used this facility?
>> >
>> > (2) The facility does not seem to permit "multiple inheritance," or
>> if it does, the semantics might be surprising.
>> > enum class Fruit { Apple, Grape, Orange };
>> > enum class Color { Red, Orange, Yellow };
>> > enum class Thing : using Fruit, Color {};
>> > // both Thing::Apple and Thing::Red have value zero, right?
>> > // does Thing::Orange exist? what is its value?
>> >
>> > Anyway, I'm sure "extending enums" has been proposed before, but I
>> haven't yet found where. N1513 Improving Enumeration Types <
>> http://www2.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1513.pdf>
>> (2003) sketches several ideas re enums, but not this one.
>> >
>> > my $.02,
>> > –Arthur
>> >
>> > --
>> > Std-Proposals mailing list
>> > Std-Proposals_at_[hidden]
>> > https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>> >
>> >
>> >
>>
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
I am a bit late to the discussion. I don't understand the metaprogramming
stuff, but I read the original mail and have some thought. I hope they are
relevant.
I think simple things should be simple to do.
I also think that there's enough things going on with the scoped enum
declaration syntax that any newly added syntax is just odd, at least the
examples I have seen.
I also agree with the thoughts that
- it's difficult to choose a way to continue the enumeration values, and
probably the best option is to continue where the base enum's author
intended it
- multiple enum inheritance is maybe too much to ask for.
With all of these in mind, here's a possible extension using new attributes:
enum class Base {
a,
b,
c
} [[extendable(c+1)]];
enum class Derived [[extends(Base)]] {
d, // = c+1
e
};
This very clearly indicates the intention that we want to be able to extend
the base enum.
This syntax is pretty self-explanatory IMO.
The author of the base enum has control over the suggested starting value
of the derived enum. This makes it easy to define bitflags as well:
enum class Base : uint32_t {
a = 0x1,
b = a << 1,
c = a << 2
} [[extendable(a << 3)]];
enum class Derived [[extends(Base)]] {
d,
e = d << 1
};
Just my two cents.
Sincerely,
Matthew
Robin Savonen Söderholm via Std-Proposals <std-proposals_at_[hidden]>
ezt írta (időpont: 2026. ápr. 27., Hét 20:51):
> Just a thought: we might be able to implement this with library features
> as well using reflections. The problem is that we have quite a few knobs to
> turn that makes it less thsn ideal to standardise, but makes it the more
> convenient for users to tailor their own versions. A pseudocode prototype
> as a library implementation could be something like:
> ```
> enum class the_base_enum {
> value_a = 0,
> value_b = 1
> };
>
> enum class some_enum_extensions {
> value_c = 2
> };
>
> using enum_with_extensions = enum_union<the_base_class,
> some_enum_extensions>;
> ```
>
> The user can in this case decide how the "union" should behave. Maybe the
> various enums should have unique values, which means that the type can just
> keep a "std::common_type_t<std::underlying_t<Enums>...>" as a member and
> have a "static_assert" that the members from each enum does not compete for
> the same representation value (or not, if the enums actually do have
> members that are supposed to mean the same thing). Or it could act more
> like a "std:: variant", effectively keeping two indices and acts as a "meta
> enum".
> The user could also potentially (unsure if current version of reflections
> allow it but that could be extended) expose all members from each enum as a
> member in the class template instantiation. I. e. meaning that if we
> continue from the code above, the implementation could provide the ability
> to do:
> ```
> auto my_value = enum_with_extensions::value_c;
> ```
>
> But I personally see a bit too many trade offs without a clear cut "most
> likely optimal in most cases" path to take to really push for it. And
> similar trade offs are seen in the compiler extension version as well.
>
> Anyhow, just my thoughts.
>
> Good evening,
> Robin
>
> On Sat, Apr 25, 2026, 10:22 Sebastian Wittmeier via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> I was only concentrating on the combination, as the metaclasses were
>> discussed.
>>
>>
>>
>> For convertibility of pointers along the inheritance chain, the Base
>> pointer itself (probably not the object instance) has to keep the actual
>> type.
>>
>>
>>
>> Or one leaves out pointer convertibility. Enums are a simple value type.
>> We can't convert between int* and float* either. But we can assign values
>> between them. Or create a std::variant. Such features can be useful for
>> enums.
>>
>>
>> -----Ursprüngliche Nachricht-----
>> *Von:* Jens Maurer <jens.maurer_at_[hidden]>
>> *Gesendet:* Sa 25.04.2026 10:03
>> *Betreff:* Re: [std-proposals] Add inheritance for Enum Class
>> enumerations
>> *An:* std-proposals_at_[hidden];
>> *CC:* Sebastian Wittmeier <wittmeier_at_[hidden]>;
>>
>>
>> On 4/25/26 01:11, Sebastian Wittmeier via Std-Proposals wrote:
>> > They could have different underlying representations:
>>
>> Yes.
>>
>> > With strong typing the compiler could add an offset for one of the
>> ancestor enum classes.
>>
>> No, that won't work.
>>
>>
>> If this hypothetical feature is just for re-using enum values
>> and allowing conversion from a "base" value to a "derived" enum type,
>> then maybe there's some merit hidden here. However, I can't see how
>> to make a "Derived*" convert to a "Base*", similar to class derivation.
>>
>>
>> Alternative syntax suggestion:
>>
>> enum class Derived {
>> using enum Base; // import the enumerators here; ugh, semicolon
>> NEXT_ENUM = whatever,
>> };
>>
>> Jens
>>
>>
>> >
>> > -----Ursprüngliche Nachricht-----
>> > *Von:* Arthur O‘Dwyer via Std-Proposals <
>> std-proposals_at_[hidden]>
>> > *Gesendet:* Fr 24.04.2026 23:10
>> > *Betreff:* Re: [std-proposals] Add inheritance for Enum Class
>> enumerations
>> > *An:* std-proposals_at_[hidden];
>> > *CC:* Arthur O‘Dwyer <arthur.j.odwyer_at_[hidden]>;
>> > On Fri, Apr 24, 2026 at 4:00 PM Gašper Ažman via Std-Proposals <
>> std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]>>
>> wrote:
>> >
>> > Note that `using enum` exists and probably does what you need.
>> >
>> >
>> > I don't think "using enum" does what Andrey wants — because I think
>> Andrey is trying to describe this other common problem instead. This
>> /r/ProgrammingLanguages thread <
>> https://www.reddit.com/r/ProgrammingLanguages/comments/rk1y4u/extending_enums/>
>> calls it "extending enums."
>> > Here's some lightly-anonymized code from a real (DNS-related)
>> codebase:
>> >
>> > enum HttpServerStat {
>> > TLS_HANDSHAKES,
>> > TLS_HANDSHAKE_ERRORS,
>> > TLS_HANDSHAKE_TIMEOUTS,
>> > [...]
>> > RESPONSE_DROPS,
>> > MAX_HTTP_SERVER_STAT_ID
>> > };
>> >
>> > enum HttpStat {
>> > // Extends HttpServerStat
>> > QUERY_COUNT_HTTP = MAX_HTTP_SERVER_STAT_ID,
>> > QUERY_BYTES_HTTP,
>> > RESPONSE_COUNT_HTTP,
>> > RESPONSE_BYTES_HTTP,
>> > [...]
>> > MAX_HTTP_STAT_ID
>> > };
>> >
>> > enum ODoHStat {
>> > // Extends HttpStat
>> > ODOH_QUERY_COUNT = MAX_HTTP_STAT_ID,
>> > ODOH_QUERY_BYTES,
>> > [...]
>> > ODOH_4XX_RESPONSE,
>> > MAX_ODOH_STAT_ID
>> > };
>> >
>> > (Sidebar: We had to make some very minor changes to the users of
>> this code for C++20, which tightened restrictions on cross-enum arithmetic
>> and comparison.)
>> > The idea is that ODoHStat "extends" HttpStat in the same way that
>> std::partial_ordering "extends" std::strong_ordering. Every value in the
>> domain of HttpStat is also in the domain of ODoHStat (although the reverse
>> is not true).
>> > Notice that this is the opposite of what class inheritance means!
>> When a /class/ ODoHStat /derives/ from HttpStat then we say that every
>> object of type ODoHStat is an object of type HttpStat (not the reverse).
>> >
>> > What we really want to be able to say here is something like
>> > enum class ODoHStat : using HttpStat {
>> > ODOH_QUERY_COUNT = MAX_HTTP_STAT_ID,
>> > ODOH_QUERY_BYTES,
>> > [...]
>> > ODOH_4XX_RESPONSE,
>> > MAX_ODOH_STAT_ID
>> > };
>> > Again, notice the inappropriateness of "inheritance" syntax here.
>> > enum ODoHStat : HttpStat { // NO!
>> > Because that syntax already has a meaning for enum declarations:
>> it's "HttpStat is the underlying type of ODoHStat; we guarantee that all
>> values of type ODoHStat will fit into an HttpStat." Which is /*not at all*/
>> what we mean here; in fact we mean the opposite: here we guarantee that all
>> values of type /HttpStat/ will fit into an /ODoHStat/.
>> >
>> > This fantasy feature would permit us to use `enum class`, and
>> expose all the enumerators of the "parent" enum as members of the "child",
>> thus:
>> > ODoHStat e = ODoHStat::QUERY_COUNT_HTTP;
>> > Today, we can't do that. We can either avoid scoped enums
>> altogether, or else we have to write
>> > ODoHStat e = static_cast<ODoHStat>(HttpStat::QUERY_COUNT_HTTP);
>> >
>> > If we got such a facility:
>> >
>> > (1) We would not want to permit the "child" enum to just start
>> listing new enumerators without an initializer for the first one:
>> > enum class ODoHStat : using HttpStat { ODOH_QUERY_COUNT,
>> ODOH_QUERY_BYTES, [...] // NO!
>> > because what would they start numbering at — zero?
>> one-more-than-the-parent-enum's-highest-enumerator?
>> std::bit_ceil-of-one-more-than-the-parent-enum's-highest-enumerator? None
>> of these are safe answers. The only safe pattern is as we do in the code
>> above: start where the parent enum tells you to start. Even then, this is
>> super fragile: if we add a new enumerator to HttpStat, that will increment
>> the values of ODoHStat's enumerators too. Arguably the author of ODoHStat
>> knew what they were signing up for when they used this facility?
>> >
>> > (2) The facility does not seem to permit "multiple inheritance," or
>> if it does, the semantics might be surprising.
>> > enum class Fruit { Apple, Grape, Orange };
>> > enum class Color { Red, Orange, Yellow };
>> > enum class Thing : using Fruit, Color {};
>> > // both Thing::Apple and Thing::Red have value zero, right?
>> > // does Thing::Orange exist? what is its value?
>> >
>> > Anyway, I'm sure "extending enums" has been proposed before, but I
>> haven't yet found where. N1513 Improving Enumeration Types <
>> http://www2.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1513.pdf>
>> (2003) sketches several ideas re enums, but not this one.
>> >
>> > my $.02,
>> > –Arthur
>> >
>> > --
>> > Std-Proposals mailing list
>> > Std-Proposals_at_[hidden]
>> > https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>> >
>> >
>> >
>>
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2026-04-27 21:44:51
