std::to_underlying是c++23新增的类型安全枚举转底层类型函数,需包含头文件,仅接受枚举类型参数,返回其声明的底层类型值,不进行范围检查,前向声明时不可用。

std::to_underlying 在 C++23 中怎么用
它只能用于 enum 或 enum class,不能用于任意整数、指针或自定义类型。C++23 才正式加入标准库,此前所有编译器都靠手写 static_cast 模拟。
最简用法就是传一个枚举值进去,它返回对应底层类型的值:
enum class Color { Red = 1, Green = 2 };
auto v = std::to_underlying(Color::Red); // 类型是 int,值为 1
- 必须包含
<utility></utility>头文件 - 参数类型必须是枚举类型(
decltype(x)是枚举),传int或unsigned char会编译失败 - 返回类型是该枚举声明的底层类型(
enum : short→short,enum class默认是int)
为什么不用 static_cast(e)?
直接 static_cast 看似等价,但有隐含风险:它不校验是否真为枚举类型。比如把一个 int 变量误传进去,编译器不会报错,运行时可能出问题。
std::to_underlying 是函数模板,做了 SFINAE / concepts 限制(C++20 起),只接受枚举类型。这是它存在的核心价值——类型安全。
- 旧代码里常见
static_cast<:underlying_type_t>>(e)</:underlying_type_t>,本质和static_cast一样,没加类型检查 - 如果你用的是 C++20 且没升级到 C++23,
std::to_underlying还不存在,别硬写 - Clang 15+、GCC 13+、MSVC 19.34+ 已支持,但需显式开启
-std=c++23
std::to_underlying 和底层类型不一致时会怎样
它不会做任何转换或截断,只是“原样转发”枚举值到其底层类型。如果枚举值超出了底层类型的表示范围,行为是未定义的(UB),和 static_cast 一样。
例如:
enum class Big : char { X = 300 }; // char 最大通常为 127
auto x = std::to_underlying(Big::X); // UB:300 无法存入 char
- 编译器一般不会报错,尤其在优化开启后
- 这种越界常发生在从网络/文件读取原始字节再转枚举时,务必先校验范围
- 不要依赖
std::to_underlying做“安全转换”,它不提供边界检查
能不能对 enum class 的私有底层类型用 to_underlying
可以,只要枚举定义可见,底层类型是否公开不影响。C++23 标准明确允许访问枚举的底层类型,哪怕它是 enum class : unsigned long long 这种显式指定的。
但注意:如果枚举是前向声明(enum class E;),而定义在别处,那么 std::to_underlying 无法实例化,因为底层类型不可知。
- 前向声明 +
std::to_underlying→ 编译失败,错误信息类似invalid use of incomplete type - 跨模块使用时,确保头文件中完整定义了枚举,不只是声明
- 没有所谓“私有底层类型”的概念;底层类型由定义决定,不是访问控制能隐藏的
std::to_underlying 找不到,八成是忘了 #include <utility></utility>,或者编译器还没切到 C++23。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











