C++ Module 2 – Types, values and expressions
C++ enums: enum class and std::to_underlying
Define scoped enumerations with enum class, convert them to and from integers safely, get -Wswitch warnings for missed cases, and build bit flags.
What you will learn
- Define scoped enumerations with an explicit underlying type
- Convert between enums and integers safely
- Detect unhandled enumerators in a switch with compiler warnings
Before you start
What you’ll learn · Before you start
What you will learn
- Define scoped enumerations with an explicit underlying type
- Convert between enums and integers safely
- Detect unhandled enumerators in a switch with compiler warnings
Before you start
On this page
An enumeration is a type whose values are a set of named constants, such as the states of a traffic light or
the days of the week. Write it as an enum class (a scoped enumeration, since C++11): its names stay inside
the type, as Light::red, and its values never turn into integers by accident. Each enumeration is stored as an
integer type, its underlying type, which you can choose (enum class Light : std::uint8_t), and when you do need
the number, std::to_underlying (C++23) gives it without spelling the type. Plain enum, the form inherited from C,
still works, but its names spill into the surrounding scope and its values convert to int silently. This lesson
compares the two, writes a state machine with a switch that the compiler checks for missing cases, converts in both
directions safely, builds bit flags, and previews how C++26 reflection turns enumerators into names, with Apple
clang 21 and GCC 16.
Plain enums and their two problems
A plain (unscoped) enum puts its enumerators into the scope around it, and they convert to int wherever an
integer would fit:
// Plain (unscoped) enums: their names spill into the surrounding scope,
// and they turn into int on their own.
#include <print>
enum Fruit { apple, banana, mango };
enum Colour { red, green, yellow };
// enum Signal { red, amber, green }; // would not compile: red and green are already taken
int main() {
int total = apple + banana + mango; // enumerators are ints in arithmetic: 0 + 1 + 2
Fruit f = mango;
bool same = (f == yellow); // compares a Fruit with a Colour: both are 2
std::println("total = {}, mango == yellow is {}", total, same);
} from session import run
run("""
clang++ --version | head -n 1
clang++ -std=c++23 -Wall -Wextra unscoped.cpp -o unscoped && ./unscoped
g++-16 --version | head -n 1
g++-16 -std=c++23 -Wall -Wextra unscoped.cpp -o unscoped && ./unscoped
# C++26 removed the comparison of two different enumeration types:
clang++ -std=c++2c -Wall -Wextra unscoped.cpp -o unscoped
g++-16 -std=c++26 -Wall -Wextra unscoped.cpp -o unscoped && ./unscoped
""") Output
$ clang++ --version | head -n 1
Apple clang version 21.0.0 (clang-2100.3.34.2)
$ clang++ -std=c++23 -Wall -Wextra unscoped.cpp -o unscoped && ./unscoped
unscoped.cpp:12:20: warning: comparison of different enumeration types ('Fruit' and 'Colour') is deprecated [-Wdeprecated-enum-compare]
12 | bool same = (f == yellow); // compares a Fruit with a Colour: both are 2
| ~ ^ ~~~~~~
1 warning generated.
total = 3, mango == yellow is true
$ g++-16 --version | head -n 1
g++-16 (Homebrew GCC 16.2.0) 16.2.0
$ g++-16 -std=c++23 -Wall -Wextra unscoped.cpp -o unscoped && ./unscoped
unscoped.cpp: In function 'int main()':
unscoped.cpp:12:20: warning: comparison between 'enum Fruit' and 'enum Colour' [-Wenum-compare]
12 | bool same = (f == yellow); // compares a Fruit with a Colour: both are 2
| ~~^~~~~~~~~
total = 3, mango == yellow is true
# C++26 removed the comparison of two different enumeration types:
$ clang++ -std=c++2c -Wall -Wextra unscoped.cpp -o unscoped
unscoped.cpp:12:20: error: invalid comparison of different enumeration types ('Fruit' and 'Colour') [-Wenum-enum-conversion]
12 | bool same = (f == yellow); // compares a Fruit with a Colour: both are 2
| ~ ^ ~~~~~~
1 error generated.
[exit status 1]
$ g++-16 -std=c++26 -Wall -Wextra unscoped.cpp -o unscoped && ./unscoped
unscoped.cpp: In function 'int main()':
unscoped.cpp:12:20: warning: comparison between 'enum Fruit' and 'enum Colour' [-Wenum-compare]
12 | bool same = (f == yellow); // compares a Fruit with a Colour: both are 2
| ~~^~~~~~~~~
total = 3, mango == yellow is true
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 unscoped_session.py
- The names leak:
redbelongs to the whole file, so a second enumeration with ared, a traffic signal say, would not compile. - The values are integers:
apple + banana + mangois 3, and aFruitcompares equal to aColourbecause both are 2. C++20 deprecated comparisons and arithmetic between two different enumeration types (P1120R0), so both compilers warn, and C++26 removed them (P2864R2): Clang 21 with-std=c++2crejects the line, while GCC 16 still only warns.
enum class: scoped and strongly typed
An enum class fixes both problems. Its enumerators are written with the type’s name, and converting one to an
integer needs a cast. This traffic light is a small state machine: the state is a Light, and next() moves it
along:
// A traffic light as a state machine: enum class for the states, a switch for the transitions.
#include <cstdint>
#include <print>
#include <string_view>
#include <utility>
enum class Light : std::uint8_t { red, green, yellow };
Light next(Light now) {
switch (now) {
case Light::red: return Light::green;
case Light::green: return Light::yellow;
case Light::yellow: return Light::red;
}
return Light::red; // reached only for a value that is not one of the enumerators: fail safe
}
std::string_view name(Light light) {
using enum Light; // C++20: red, green and yellow can be written without Light::
switch (light) {
case red: return "red";
case green: return "green";
case yellow: return "yellow";
}
return "not a Light value";
}
int main() {
Light light = Light::red;
for (int step = 0; step < 4; ++step) {
std::println("{} (stored as {})", name(light), std::to_underlying(light));
light = next(light);
}
std::println("sizeof(Light) = {}", sizeof(Light));
// int n = light; // would not compile: no implicit conversion to int
// if (light == 0) {} // nor a comparison with an int
} from session import run
run("""
clang++ -std=c++23 -Wall -Wextra traffic_light.cpp -o traffic_light && ./traffic_light
g++-16 -std=c++23 -Wall -Wextra traffic_light.cpp -o traffic_light && ./traffic_light
""") Output
$ clang++ -std=c++23 -Wall -Wextra traffic_light.cpp -o traffic_light && ./traffic_light red (stored as 0) green (stored as 1) yellow (stored as 2) red (stored as 0) sizeof(Light) = 1 $ g++-16 -std=c++23 -Wall -Wextra traffic_light.cpp -o traffic_light && ./traffic_light red (stored as 0) green (stored as 1) yellow (stored as 2) red (stored as 0) sizeof(Light) = 1
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 traffic_light_session.py
The traffic light of traffic_light.cpp as a state machine
Text description of the diagram
The diagram shows the three enumerators of enum class Light as boxes, each with the integer it is stored as.
- Light::red, stored as 0, has an arrow labelled next() to Light::green.
- Light::green, stored as 1, has an arrow labelled next() to Light::yellow.
- Light::yellow, stored as 2, has an arrow labelled next() back to Light::red, which closes the cycle.
What the example shows:
- The underlying type.
: std::uint8_tstores eachLightin one byte, which the output confirms withsizeof(Light) = 1; without it, anenum classusesint. Choose a type when the size matters (a file format, a network message, millions of values) and leave it out otherwise, as the C++ Core Guidelines advise. - No implicit conversion. The two commented lines at the end of
mainwould not compile: aLightis not anint, andlight == 0compares two different kinds of thing. using enum(C++20, P1099R5) brings the enumerators into a scope, so the cases inname()can sayredinstead ofLight::red.- Formatting.
std::printlnprints the result ofstd::to_underlyingas a number even though it is astd::uint8_t;std::cout << std::uint8_t{0}would print it as a character, the one whose code is 0.
Converting between enums and integers
From an enum to its integer, use std::to_underlying (C++23, P1682R3); it is the short form of
static_cast<std::underlying_type_t<E>>(e). From an integer to an enum, use static_cast, and check the value first,
because the cast accepts more than the enumerators:
conversions.cpp
// Converting between an enum and its integer, in both directions.
#include <cstdint>
#include <optional>
#include <print>
#include <type_traits>
#include <utility>
enum class Floor : std::int8_t { basement = -1, ground = 0, first = 1, second = 2 };
// Integer to enum: static_cast accepts any value of the underlying type,
// so check the range first.
std::optional<Floor> to_floor(int n) {
if (n < -1 || n > 2) return std::nullopt;
return static_cast<Floor>(n);
}
int main() {
static_assert(std::is_same_v<std::underlying_type_t<Floor>, std::int8_t>);
// Enum to integer: std::to_underlying (C++23) is the short form
// of the static_cast below it.
const auto a = std::to_underlying(Floor::basement);
const auto b = static_cast<std::underlying_type_t<Floor>>(Floor::basement);
std::println("basement = {} and {}, of type std::int8_t: {}", a, b,
std::is_same_v<decltype(a), const std::int8_t>);
for (int n : {2, 5}) {
const auto f = to_floor(n);
std::println("to_floor({}): {}", n, f ? "a valid Floor" : "no such floor");
}
// allowed: 5 fits in std::int8_t, but it names no floor
const Floor odd = static_cast<Floor>(5);
std::println("static_cast<Floor>(5) holds {}", std::to_underlying(odd));
} unscoped_range.cpp
// An enum without a fixed underlying type has a range set by its enumerators: here 0 to 1.
// Converting 4 into it is undefined behaviour, which a constant expression must not contain.
enum Size { small, large };
constexpr Size s = static_cast<Size>(4);
int main() { return s; } from session import run
run("""
clang++ -std=c++23 -Wall -Wextra conversions.cpp -o conversions && ./conversions
g++-16 -std=c++23 -Wall -Wextra conversions.cpp -o conversions && ./conversions
clang++ -std=c++23 -Wall -Wextra unscoped_range.cpp -o unscoped_range
g++-16 -std=c++23 -Wall -Wextra unscoped_range.cpp -o unscoped_range && ./unscoped_range
""") Output
$ clang++ -std=c++23 -Wall -Wextra conversions.cpp -o conversions && ./conversions
basement = -1 and -1, of type std::int8_t: true
to_floor(2): a valid Floor
to_floor(5): no such floor
static_cast<Floor>(5) holds 5
$ g++-16 -std=c++23 -Wall -Wextra conversions.cpp -o conversions && ./conversions
basement = -1 and -1, of type std::int8_t: true
to_floor(2): a valid Floor
to_floor(5): no such floor
static_cast<Floor>(5) holds 5
$ clang++ -std=c++23 -Wall -Wextra unscoped_range.cpp -o unscoped_range
unscoped_range.cpp:5:16: error: constexpr variable 's' must be initialized by a constant expression
5 | constexpr Size s = static_cast<Size>(4);
| ^ ~~~~~~~~~~~~~~~~~~~~
unscoped_range.cpp:5:20: note: integer value 4 is outside the valid range of values [0, 1] for the enumeration type 'Size'
5 | constexpr Size s = static_cast<Size>(4);
| ^
1 error generated.
[exit status 1]
$ g++-16 -std=c++23 -Wall -Wextra unscoped_range.cpp -o unscoped_range && ./unscoped_range
[exit status 4]
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 conversions_session.py
For an enumeration with a fixed underlying type, every value of that type is a valid value of the enumeration (section
9.7.1 of the standard), so static_cast<Floor>(5) is allowed and holds 5, a floor that does not exist. That is why
to_floor checks the range and returns std::optional<Floor>: the caller cannot forget that a number may have no
floor. A plain enum without a fixed type is stricter: its values are only those that fit in the bits its
enumerators need, 0 and 1 for Size, and converting anything else is undefined behaviour. In a constant expression
Clang rejects static_cast<Size>(4); GCC 16 accepts it, and the program even exits with status 4.
switch over an enum, checked by the compiler
A switch over an enumeration is where enums pay off: when a new enumerator is added, the compiler can find every
switch that does not handle it. -Wswitch, part of -Wall, warns when a switch without a default misses an
enumerator:
// A fourth state was added to Light, but one switch was not updated.
// -Wswitch (part of -Wall) notices.
#include <cstdint>
#include <string_view>
enum class Light : std::uint8_t { red, green, yellow, flashing_yellow };
std::string_view name(Light light) {
switch (light) {
case Light::red: return "red";
case Light::green: return "green";
case Light::yellow: return "yellow";
}
return "?";
}
std::string_view advice(Light light) {
switch (light) {
case Light::red: return "stop";
// a default hides missing enumerators from -Wswitch
default: return "go carefully";
}
}
int main() { return name(Light::flashing_yellow).size() + advice(Light::green).size(); } from session import run
run("""
clang++ -std=c++23 -Wall -Wextra missing_case.cpp -o missing_case
g++-16 -std=c++23 -Wall -Wextra missing_case.cpp -o missing_case
# -Wswitch-enum also reports the switch that has a default case (only the warning lines are kept):
clang++ -std=c++23 -Wall -Wextra -Wswitch-enum missing_case.cpp -o missing_case 2>&1 | grep warning
g++-16 -std=c++23 -Wall -Wextra -Wswitch-enum missing_case.cpp -o missing_case 2>&1 | grep warning
""") Output
$ clang++ -std=c++23 -Wall -Wextra missing_case.cpp -o missing_case
missing_case.cpp:9:13: warning: enumeration value 'flashing_yellow' not handled in switch [-Wswitch]
9 | switch (light) {
| ^~~~~
missing_case.cpp:9:13: note: add missing switch cases
9 | switch (light) {
| ^
10 | case Light::red: return "red";
11 | case Light::green: return "green";
12 | case Light::yellow: return "yellow";
13 | }
1 warning generated.
$ g++-16 -std=c++23 -Wall -Wextra missing_case.cpp -o missing_case
missing_case.cpp: In function 'std::string_view name(Light)':
missing_case.cpp:9:12: warning: enumeration value 'flashing_yellow' not handled in switch [-Wswitch]
9 | switch (light) {
| ^
# -Wswitch-enum also reports the switch that has a default case (only the warning lines are kept):
$ clang++ -std=c++23 -Wall -Wextra -Wswitch-enum missing_case.cpp -o missing_case 2>&1 | grep warning
missing_case.cpp:9:13: warning: enumeration value 'flashing_yellow' not handled in switch [-Wswitch]
missing_case.cpp:18:13: warning: enumeration values 'green', 'yellow', and 'flashing_yellow' not explicitly handled in switch [-Wswitch-enum]
2 warnings generated.
$ g++-16 -std=c++23 -Wall -Wextra -Wswitch-enum missing_case.cpp -o missing_case 2>&1 | grep warning
missing_case.cpp:9:12: warning: enumeration value 'flashing_yellow' not handled in switch [-Wswitch]
missing_case.cpp:18:12: warning: enumeration value 'green' not handled in switch [-Wswitch-enum]
missing_case.cpp:18:12: warning: enumeration value 'yellow' not handled in switch [-Wswitch-enum]
missing_case.cpp:18:12: warning: enumeration value 'flashing_yellow' not handled in switch [-Wswitch-enum]
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 missing_case_session.py
Both compilers report flashing_yellow in name(), and say nothing about advice(), whose default covers every
value. That is the cost of a default in a switch over an enum: it silences the warning for every enumerator added
later. Leave the default out, handle every enumerator, and put a fallback after the switch, as next() does above.
When a project wants every switch checked anyway, -Wswitch-enum warns even when a default is present, as the
last two commands show.
Bit flags with enum class
An enum class can also name single bits, so that one value holds a set of flags, like the permissions of a file.
Because there is no implicit conversion to an integer, you define | and & for the type once, and every use stays
type-safe. This builds on the masks of the bitwise operators lesson:
// Bit flags with enum class: each permission is one bit,
// and two small operators combine and test them.
#include <cstdint>
#include <print>
#include <utility>
enum class Permission : std::uint8_t {
none = 0,
read = 1 << 0, // 0b001
write = 1 << 1, // 0b010
execute = 1 << 2, // 0b100
};
constexpr Permission operator|(Permission a, Permission b) {
return static_cast<Permission>(std::to_underlying(a) | std::to_underlying(b));
}
constexpr Permission operator&(Permission a, Permission b) {
return static_cast<Permission>(std::to_underlying(a) & std::to_underlying(b));
}
constexpr bool has(Permission set, Permission p) { return (set & p) == p; }
int main() {
constexpr Permission owner = Permission::read | Permission::write | Permission::execute;
constexpr Permission guest = Permission::read;
static_assert(has(owner, Permission::write) && !has(guest, Permission::write));
for (auto [who, set] : {std::pair{"owner", owner}, std::pair{"guest", guest}}) {
std::println("{}: {:03b} read={} write={} execute={}", who, std::to_underlying(set),
has(set, Permission::read), has(set, Permission::write), has(set, Permission::execute));
}
} from session import run
run("""
clang++ -std=c++23 -Wall -Wextra permissions.cpp -o permissions && ./permissions
g++-16 -std=c++23 -Wall -Wextra permissions.cpp -o permissions && ./permissions
""") Output
$ clang++ -std=c++23 -Wall -Wextra permissions.cpp -o permissions && ./permissions owner: 111 read=true write=true execute=true guest: 001 read=true write=false execute=false $ g++-16 -std=c++23 -Wall -Wextra permissions.cpp -o permissions && ./permissions owner: 111 read=true write=true execute=true guest: 001 read=true write=false execute=false
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 permissions_session.py
owner holds all three bits, 111, and guest only the read bit. The operators are constexpr, so even the
static_assert can use them, and a Permission still cannot be mixed up with an ordinary integer.
Turning an enumerator into its name
C++23 has no way to ask an enumeration for the names of its enumerators, so code that prints them keeps a table by
hand, in the same order as the enumeration, and has to be updated with it. C++26 reflection (P2996R13) lets the
compiler list them. GCC 16 implements it behind -std=c++26 -freflection; Apple clang 21 does not, which the
feature-test macro __cpp_impl_reflection detects:
// Names of enumerators, two ways: a table written by hand (C++23),
// and reflection (C++26, today with GCC 16 only).
#include <array>
#include <print>
#include <string_view>
#include <utility>
enum class Light { red, green, yellow };
// By hand: the table must be kept in the same order as the enum.
constexpr std::array<std::string_view, 3> light_names{"red", "green", "yellow"};
constexpr std::string_view name_by_hand(Light l) { return light_names[std::to_underlying(l)]; }
#if __cpp_impl_reflection
#include <meta>
// By reflection: the compiler lists the enumerators of E, with their names.
template <typename E>
constexpr std::string_view name_by_reflection(E value) {
template for (constexpr auto e : std::define_static_array(std::meta::enumerators_of(^^E))) {
if (value == [:e:]) return std::meta::identifier_of(e);
}
return "?";
}
#endif
int main() {
std::println("by hand: {}", name_by_hand(Light::yellow));
#if __cpp_impl_reflection
std::println("by reflection: {}", name_by_reflection(Light::yellow));
#else
std::println("this compiler has no reflection");
#endif
} from session import run
run("""
g++-16 -std=c++26 -freflection -Wall -Wextra enum_names.cpp -o enum_names && ./enum_names
clang++ -std=c++2c -Wall -Wextra enum_names.cpp -o enum_names && ./enum_names
""") Output
$ g++-16 -std=c++26 -freflection -Wall -Wextra enum_names.cpp -o enum_names && ./enum_names by hand: yellow by reflection: yellow $ clang++ -std=c++2c -Wall -Wextra enum_names.cpp -o enum_names && ./enum_names by hand: yellow this compiler has no reflection
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 enum_names_session.py
^^E reflects the type, std::meta::enumerators_of lists its enumerators, template for (an expansion statement)
loops over them while compiling, and std::meta::identifier_of gives each name. The track’s module on C++26 previews
covers reflection in depth; until your compilers support it, keep a table, and check it with a static_assert on
its size.
Exercise: weekdays as text
Write to_string, which returns the lower-case name of a Weekday, and parse_weekday, which turns such a name back
into a Weekday, or into no value for anything else. The checks must all print ok:
// Exercise: write to_string and parse_weekday.
// Build and run this file: every check must say "ok".
// to_string(Weekday::monday) gives "monday"; parse_weekday("monday") gives Weekday::monday;
// parse_weekday of anything else ("Monday", "", "funday") gives no value.
#include <optional>
#include <print>
#include <string_view>
enum class Weekday { monday, tuesday, wednesday, thursday, friday, saturday, sunday };
std::string_view to_string(Weekday day) {
(void)day;
return ""; // replace this
}
std::optional<Weekday> parse_weekday(std::string_view text) {
(void)text;
return std::nullopt; // replace this
}
int failures = 0;
void check(bool passed, std::string_view what) {
std::println("{} {}", passed ? "ok " : "FAILED", what);
if (!passed) ++failures;
}
int main() {
check(to_string(Weekday::monday) == "monday", "to_string(monday)");
check(to_string(Weekday::sunday) == "sunday", "to_string(sunday)");
check(parse_weekday("friday") == Weekday::friday, "parse_weekday(\"friday\")");
check(!parse_weekday("Friday"), "names are lower case: \"Friday\" gives no value");
check(!parse_weekday("") && !parse_weekday("funday"), "empty text and unknown names give no value");
bool round_trip = true;
for (int i = 0; i < 7; ++i) {
const auto day = static_cast<Weekday>(i);
round_trip = round_trip && parse_weekday(to_string(day)) == day;
}
check(round_trip, "parse_weekday(to_string(d)) == d for all seven days");
std::println("{} of 6 checks failed", failures);
return failures == 0 ? 0 : 1;
} from session import run
run("""
clang++ -std=c++23 -Wall -Wextra -fsanitize=address,undefined weekday_exercise.cpp -o weekday_exercise && ./weekday_exercise
""") Output
$ clang++ -std=c++23 -Wall -Wextra -fsanitize=address,undefined weekday_exercise.cpp -o weekday_exercise && ./weekday_exercise
FAILED to_string(monday)
FAILED to_string(sunday)
FAILED parse_weekday("friday")
ok names are lower case: "Friday" gives no value
ok empty text and unknown names give no value
FAILED parse_weekday(to_string(d)) == d for all seven days
4 of 6 checks failed
[exit status 1]
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 weekday_exercise_session.py
The starter returns empty results, so two checks pass by accident and four fail. First hint: keep the seven names in
a constexpr std::array<std::string_view, 7> in enumeration order and index it with std::to_underlying(day); then
parse_weekday can loop over the seven days and compare.
Self-check
Check yourself
5 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.
Interview questions
What is the difference between enum and enum class? A plain enum puts its enumerators into the enclosing
scope, and its values convert to integers implicitly, so they can be added, compared with other enumerations or
passed where an int is expected. An enum class keeps its enumerators inside its own scope (Color::red), never
converts implicitly (static_cast or std::to_underlying is required), and has a fixed underlying type, int
unless another is given. Prefer enum class; plain enums remain for old code and C interfaces.
Key takeaways
- Prefer
enum class: scoped names, no implicit conversions,intas the underlying type unless you choose one. std::to_underlying(C++23) converts an enumerator to its integer;static_castconverts back, and accepts any value of the underlying type, so check the range and returnstd::optionalfrom a parser.- Converting a value outside the range of a plain enum without a fixed type is undefined behaviour.
-Wswitch(in-Wall) reports enumerators missing from aswitchwithoutdefault;-Wswitch-enumchecks the ones withdefaulttoo.using enum(C++20) shortens the cases of aswitch.- Bit flags work with
enum classonce you define|and&. - Names of enumerators need a hand-written table in C++23; C++26 reflection lists them, today with GCC 16 and
-freflection.
References
- Working Draft, Programming Languages: C++ (N4950), 9.7.1 Enumeration declarations, 9.7.2 The using enum declaration, 7.6.1.9 Static cast, 22.2.8 to_underlying (ISO/IEC JTC1/SC22/WG21)
- P1682R3: std::to_underlying for enumerations (ISO/IEC JTC1/SC22/WG21)
- P1099R5: Using Enum (ISO/IEC JTC1/SC22/WG21)
- P1120R0: Consistency improvements for <=> and other comparison operators (ISO/IEC JTC1/SC22/WG21)
- P2864R2: Remove Deprecated Arithmetic Conversion on Enumerations From C++26 (ISO/IEC JTC1/SC22/WG21)
- P2996R13: Reflection for C++26 (ISO/IEC JTC1/SC22/WG21)
- GCC 16 Release Series, Changes, New Features, and Fixes (GNU Project (GCC))
- Options to Request or Suppress Warnings (-Wswitch, -Wswitch-enum) (GNU Project (GCC))
- C++ Core Guidelines: Enum.3 Prefer class enums over plain enums (Standard C++ Foundation)
- C++ Core Guidelines: Enum.7 Specify the underlying type of an enumeration only when necessary (Standard C++ Foundation)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress