Date: Sat, 25 Apr 2026 07:42:05 +0200
Sometimes we are using enums just because it is the only thing that we have. I‘m not entirely sure if we need to extend enums to get some of the things we want. Specifically, I‘m thinking of two things that might give some inspiration of how things could be solved.
1. I‘m thinking about std::expected, std::error_code, and std::error_condition. Here, we can create a hierarchy of error codes that can be used together. There is a way to specify how error codes decay into each other. IIRC both error codes and error conditions are backed by enums. However, those enums can have overlapping values. The disadvantage probably is that we cannot switch over these. I would hope that we get pattern matching and that is possible with pattern matching instead. Currently, using both error codes and error conditions requires allot of boilerplate code. Hopefully, future reflection with queue injection can help with this. This is not meant as a solution to the original problem at hand, but as an inspiration for how we might think differently about enum hierarchies.
2. In many cases we might want to use enums for flags. Currently, this is quite cumbersome to write. Years ago Herb Sutter talked about his vision of metaclasses in the context of reflection. One of his examples was to write a metaclass that implements flags properly (using power-of-two for enum values). In the same way we might write some metaclass in the future that does some form of inheritance for enums. Actually, I‘m thinking if we *want* different enums to be convertible between each other when using inheritance. Or with reflection we might just specify another enum and reflection will copy all definitions from the other enum into our enum. If we want to be able to convert from a parent enum class, we would need to specify some conversion operators. Especially with metaclasses (I hope we get them some time) we would have ways of making this work.
On Apr 24, 2026, at 11:09 PM, Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden]> wrote:
--On Fri, Apr 24, 2026 at 4:00 PM Gašper Ažman via Std-Proposals <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 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 likeenum 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 writeODoHStat 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 (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
Received on 2026-04-25 05:42:19
