std::to_underlying 在 c++23 中引入,旧标准不支持;此前需用 static_cast 安全转换枚举,避免未定义行为。

std::to_underlying 在 C++23 才可用,别在旧标准里找它
这个函数根本不存在于 C++20 及更早版本。如果你在 clang 15、GCC 13 或 MSVC 19.35+ 上启用了 -std=c++23(或 /std:c++23),它才在 <utility></utility> 中定义;否则编译会直接报错 ‘to_underlying’ is not a member of ‘std’。C++23 之前只能手写等价逻辑。
替代方案:用 static_cast<:underlying_type_t>> 安全转换
这是最常用、最兼容的做法,适用于所有支持 enum class 的标准(C++11 起)。关键点在于必须显式指定底层类型,避免无作用域枚举的隐式整型提升问题。
常见错误现象:
- 对无作用域枚举(如
enum Color { Red, Green };)直接static_cast<int>(Red)</int>看似可行,但若枚举值超出int范围(比如含0xFFFFFFFFULL),行为未定义 - 漏掉
std::underlying_type_t,硬写int,当枚举声明为enum : long long { X = 1LL 时会截断
正确写法示例:
enum class Status : uint8_t { OK = 0, ERROR = 1 };
auto val = static_cast<:underlying_type_t>>(Status::OK); // 类型是 uint8_t,不是 int
</:underlying_type_t>
为什么不用 C 风格转换或 reinterpret_cast
C 风格转换((int)e)和 reinterpret_cast 在枚举场景下既不安全也不必要。前者忽略底层类型约束,后者语义错误——枚举到其底层类型的转换是值转换(value conversion),不是位模式重解释。
使用场景差异:
-
static_cast是唯一标准允许的、明确定义行为的转换方式 - 某些静态分析工具(如 clang-tidy)会警告 C 风格转换枚举,因为易掩盖底层类型不匹配
- 模板代码中若泛化处理枚举,
static_cast<:underlying_type_t>>(e)</:underlying_type_t>可被 SFINAE 或concepts约束,而 C 风格转换无法参与编译期检查
std::to_underlying 的实际行为就是封装了一次 static_cast
它的实现非常直白:constexpr auto to_underlying(E e) noexcept { return static_cast<:underlying_type_t>>(e); }</:underlying_type_t>。所以它不提供额外安全性或新能力,只省去重复写模板参数的麻烦。
性能与兼容性影响:
- 零开销:纯编译期转换,生成的汇编和手写
static_cast完全一致 - 仅限
enum class和有明确底层类型的无作用域枚举;对传统无作用域枚举(如enum E { A };)仍需先用std::underlying_type推导,否则编译失败 - 如果项目需支持 C++20 或更老标准,直接用
static_cast更稳妥,无需条件编译宏包裹
真正容易被忽略的是:即便用了 std::to_underlying,也得确保枚举本身有固定底层类型——否则像 enum E { X }; 这种未指定底层类型的无作用域枚举,std::underlying_type_t<e></e> 本身就未定义,调用它会导致编译错误。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











