C++23stlexpert
std::to_underlying (C++23 Addition)
C++23 · Completing Modern · Compiler flag: -std=c++23
Explanation
Converts an enum to its underlying type.
Real-World Scenario
Convert an enum to an integer for serialization in a game.
Quick Snippet
snippet.cpp
#include <utility> enum class E { A = 1 }; auto val = std::to_underlying(E::A);Full Example
to_underlying.cpp
// CodeNebula - C++23 Example: std::to_underlying
// Compile: g++ -std=c++23 -Wall -Wextra -o example to_underlying.cpp
// Note: Requires GCC 13+ / Clang 17+
#include <iostream>
#include <type_traits>
#include <utility>
// std::to_underlying converts a scoped enum to its underlying integer type.
// It replaces the verbose static_cast<std::underlying_type_t<E>>(value) pattern.
enum class Color : unsigned char { Red = 1, Green = 2, Blue = 4 };
enum class Flags : unsigned int { None = 0, Read = 1, Write = 2, Execute = 4 };
enum class Severity : int { Debug = -1, Info = 0, Warning = 1, Error = 2 };
// Generic flag printer using to_underlying
template <typename E>
void print_flag_value(const char* name, E value) {
std::cout << name << " = " << std::to_underlying(value) << "\n";
}
// Combine flags using to_underlying for bitwise ops
Flags operator|(Flags a, Flags b) {
return static_cast<Flags>(std::to_underlying(a) | std::to_underlying(b));
}
bool has_flag(Flags set, Flags flag) {
return (std::to_underlying(set) & std::to_underlying(flag)) != 0;
}
int main() {
std::cout << "=== std::to_underlying ===\n\n";
// Basic conversion
std::cout << "Color::Red = " << std::to_underlying(Color::Red) << "\n";
std::cout << "Color::Green = " << std::to_underlying(Color::Green) << "\n";
std::cout << "Color::Blue = " << std::to_underlying(Color::Blue) << "\n\n";
// Negative underlying values
std::cout << "Severity::Debug = " << std::to_underlying(Severity::Debug) << "\n";
std::cout << "Severity::Warning = " << std::to_underlying(Severity::Warning) << "\n\n";
// Combining flags
Flags perms = Flags::Read | Flags::Write;
std::cout << "Read | Write = " << std::to_underlying(perms) << "\n";
std::cout << "Has Read? " << (has_flag(perms, Flags::Read) ? "yes" : "no") << "\n";
std::cout << "Has Execute? " << (has_flag(perms, Flags::Execute) ? "yes" : "no") << "\n\n";
// Type verification
auto val = std::to_underlying(Color::Red);
std::cout << "to_underlying(Color) is unsigned char? "
<< std::is_same_v<decltype(val), unsigned char> << "\n";
// Generic usage
print_flag_value("Flags::Execute", Flags::Execute);
return 0;
}
// Expected output:
// === std::to_underlying ===
//
// Color::Red = 1
// Color::Green = 2
// Color::Blue = 4
//
// Severity::Debug = -1
// Severity::Warning = 1
//
// Read | Write = 3
// Has Read? yes
// Has Execute? no
//
// to_underlying(Color) is unsigned char? 1
// Flags::Execute = 4
Run command
g++ -std=c++23 -Wall -Wextra -o example to_underlying.cpp