August 4th, 2024

Enum class improvements for C++17, C++20 and C++23

Enhancements to C++ enum classes in versions 17, 20, and 23 improve code safety and usability, introducing features like brace initialization, "using enum," and std::to_underlying for better readability and maintainability.

Read original articleLink Icon
FrustrationSkepticismConfusion
Enum class improvements for C++17, C++20 and C++23

The article discusses enhancements to enum classes in C++ across versions 17, 20, and 23, highlighting improvements that enhance code safety and usability. Enum classes, which provide a type-safe way to define named constants, prevent implicit conversions to integers, thus reducing misuse. In C++17, brace initialization from the underlying type was introduced, allowing for more flexible initialization while maintaining safety. C++20 added the "using enum" feature, which simplifies the usage of enumerators by bringing them into the current scope without losing type safety. This reduces verbosity in code, making it cleaner and easier to read. C++23 introduced the std::to_underlying utility, which allows for straightforward conversion of enum values to their underlying integral types, improving code readability and reducing the need for explicit casting. The article also mentions potential future improvements, such as C++26 reflections, which could enable converting enums to strings, further enhancing their usability. Overall, these advancements in enum classes across the recent C++ standards aim to provide developers with more powerful tools for writing safe and maintainable code.

AI: What people are saying
The comments reflect a mix of opinions on the enhancements to C++ enum classes, with several common themes emerging.
  • Many users express dissatisfaction with the usability of the new features, particularly the "using enum" syntax and its implications in switch statements.
  • Concerns are raised about type safety, with some commenters noting that enums can still accept invalid values, undermining their intended purpose.
  • There is a preference for more explicit enum usage, with some users arguing that the new features complicate rather than simplify code.
  • Critiques highlight that the improvements may not address fundamental issues with enums in C++, leading to frustration among developers.
  • Some commenters question the overall necessity and effectiveness of the changes, suggesting that they do not significantly enhance the language.
Link Icon 14 comments
By @lpribis - 9 months

    enum class Handle : uint32_t { Invalid = 0 }; 
    Handle h { 42 }; // OK
One of their examples demonstrates the number one issue for me with enums, which was not fixed with `enum class`. Since values outside the range of the type are valid, you are constantly needing to check for invalid values in any function that takes an enum [class]. Ruins any attempt at "parse, don't validate" style in c++ and completely ruins the "type safety" which c++ people are always going on about.
By @fouronnes3 - 9 months
Union, inheritance, dynamic_cast, enum class, std::variant... when all we needed all along was proper sum types.
By @James_K - 9 months
> C++20 introduced the `using enum` syntax, which enhances the usability of enums

Out of context, this is a very funny thing to say.

By @patrick451 - 9 months

    enum class Handle : uint32_t { Invalid = 0 }; 
    // process({10}); // error
    process(Handle{10});
> In C++14, you could use process(static_cast<Handle>(10)); so, as you can see, the C++17 version is much better.

100% disagree that the c++17 version is better. It just lets you right broken code that doesn't look broken.

By @jeffbee - 9 months
Odd that it says

  auto value = std::to_underlying(p); // C++23
is "more expressive" than

  uint8_t value = static_cast<uint8_t>(Permissions::Read);
The latter seems clearly more expressive, not less. You could tighten it up a bit by using auto on the LHS instead of the redundant uint8_t. In the former I don't know what's going on and I have to go read another header to figure out the type of `value`.
By @westurner - 9 months
Speaking of enums, what's a better serialization framework for C++ like Serde in Rust, and then what about Linked Data support and of course also form validation.

Linked Data triples have (subject, predicate, object) and quads have (graph, subject, predicate, object).

RDF has URIs for all Subjects and Predicates.

RDF Objects may be URIs or literal values like xsd:string, xsd:float64, xsd:int (32bit signed value), xsd:integer, xsd:long, xsd:time, xsd:dateTime, xsd:duration.

RDFS then defines Classes and Properties, identified by string URIs.

How best to get from an Enum with (type,attr, {range of values}) to an rdfs:range definition in a schema with a URI prefix?

Python has dataclasses which is newer than attrs, but serde also emits Python pickles

By @account42 - 9 months
It's too bad that using enum is not emplicit for the cases in switch statements.
By @citizen_friend - 9 months
How many meanings of the word emum do we need? Whose code does this improve?
By @WhereIsTheTruth - 9 months
All that crap is the reason I never bother with enums in all these C like languages

     set_player_color(player, .RED);
That should be the way to use them, it's concise and typesafe

    set_color(Color::RED);
Why repeat yourself?

It's one of the things I love about Swift and Zig

    int main() {
        using enum ComputeStatus;
        ComputeStatus s = NotEnoughMemory;
    }

now you have polluted the scope.. C++ have lost the plot.. they understood the issue, but they came up with a solution that's worse...
By @OvbiousError - 9 months
Reflection is going to be a game-changer for C++. Finally!
By @wordofx - 9 months
I don’t feel like it’s an improvement. Personally prefer the explicit enum usage.
By @crowdstriker - 9 months
Imagine still using c++ in 2024 lmao.