std::to_underlying是c++23新增函数,要求枚举有显式底层类型(如enum class e : int或unscoped enum : uint8_t),旧标准需手动用static_cast(e),并确保e为枚举类型。

std::to_underlying 是 C++23 新增的,C++20 及更早版本不能直接用
如果你编译报错 ‘to_underlying’ is not a member of ‘std’,不是写错了,是标准库还没提供。GCC 12、Clang 15、MSVC 19.32 起才开始支持 C++23 的 std::to_underlying,且需显式开启 -std=c++23(或 -std=gnu++23)。
旧项目若无法升级标准,得手动转型:static_cast<:underlying_type_t>> (e)</:underlying_type_t> —— 注意别漏掉 std::underlying_type_t 这个模板别名,直接写 int 会出问题,因为枚举底层类型可能为 short 或 long long。
必须作用于有固定底层类型的枚举(scoped or unscoped with explicit type)
std::to_underlying 接受的是一个枚举值,但前提是该枚举声明时指定了底层类型(哪怕只是默认的 int)。无底层类型声明的非限定枚举(unscoped enum without type)在 C++23 中仍不被 std::to_underlying 接受:
enum Color { Red, Green }; // ❌ 编译失败:no matching function for call to ‘to_underlying’
enum class Status : uint8_t { OK, Err }; // ✅ OK
enum Direction : int { Left, Right }; // ✅ OK,即使没用 class
原因在于:未指定底层类型的 unscoped enum 类型本身不保证可隐式转为整数,而 std::to_underlying 的设计目标是“安全提取已知底层表示”,不是做隐式转换。
它只做一层转换,不处理枚举值越界或未定义行为
std::to_underlying 不验证输入值是否在枚举合法范围内。如果传入一个通过位运算或强制转型构造的非法枚举值,它照样返回对应整数 —— 这不是 bug,是设计使然:
- 它等价于
static_cast<:underlying_type_t>>(e)</:underlying_type_t>,纯编译期转换 - 不会触发
std::is_enum_v检查以外的运行时约束 - 对
enum class E : char { A = -1 };,传入E{-129}(溢出char)会导致未定义行为,std::to_underlying不拦截
所以,校验枚举值合法性(比如是否落在 E::A 到 E::Z 之间)仍需业务代码自行处理,别指望这个函数帮你兜底。
替代方案要小心 std::underlying_type_t 的 SFINAE 边界
手写兼容 C++11 的等效逻辑时,常见错误是直接写 static_cast<int>(e)</int>。正确做法是依赖 std::underlying_type:
template<typename e>
constexpr std::underlying_type_t<e> to_underlying(E e) noexcept {
return static_cast<:underlying_type_t>>(e);
}</:underlying_type_t></e></typename>
但注意:std::underlying_type 对非枚举类型是未定义行为(SFINAE 不适用),所以调用前务必确保 E 是枚举类型。可用 static_assert(std::is_enum_v<e>)</e> 加一层防护;否则模板实例化失败时错误信息会非常晦涩,比如 GCC 报 ‘underlying_type’ is not a member of ‘std’,实际是因为你传了 int 进去。
真正在意兼容性和健壮性时,连这个手写函数都建议加 enable_if 或 C++20 requires 约束,否则很容易在泛型上下文中误用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











