std::to_underlying仅接受枚举值,不接受引用、指针或包装器;返回其定义的底层类型而非固定int;本质是static_cast封装,零开销;需显式指定底层类型以保跨平台一致。

直接用 std::to_underlying 是安全的,前提是传入的是枚举类型的纯右值或左值,不能是引用、指针或临时对象包装器(如 std::ref)。
为什么 std::to_underlying 会编译失败?常见误传类型
它只接受枚举类型的值参数(T),不重载引用(T&)、指针(T*)或包装器版本。一旦传错,编译器报错类似:no matching function for call to ‘to_underlying’。
-
std::to_underlying(e)✅ 正确:e 是enum class类型变量或字面量 -
std::to_underlying(&e)❌ 错误:传了地址,类型是Color* -
std::to_underlying(std::ref(e))❌ 错误:std::reference_wrapper不是枚举类型 -
std::to_underlying(std::move(e))⚠️ 语法合法但没必要:std::move(e)仍是值类别,但掩盖意图,易误导后续维护者
底层类型不明确时,返回值类型不是固定 int
std::to_underlying 返回的是该枚举实际的底层类型——由定义决定,不是硬编码为 int。如果你假设结果能无损存进 int16_t,但枚举实际底层是 long(比如含大值),就可能截断或触发警告。
- 显式指定底层类型最稳妥:
enum class Status : uint8_t { OK = 0, Err = 255 };→std::to_underlying(Status::Err)返回uint8_t - 没指定底层类型时(如
enum class E { A = 1000 }),编译器选足够大的类型(可能是int或long),跨平台可能不一致 - 安全做法:用
auto接收,或显式写成std::underlying_type_t<e></e>,别硬写int
和 static_cast 的关系:不是替代,是封装
std::to_underlying 的实现就是一行 static_cast<:underlying_type_t>>(e)</:underlying_type_t>。它不提供额外安全性,只省去模板参数重复书写,提升可读性。
- 性能完全一致:零开销,生成汇编和手写
static_cast一样 - 仍需警惕底层类型语义:比如
enum class E : uint8_t { NEG = 255 },std::to_underlying(E::NEG)得到的是255u,不是-1 - 模板泛化场景中,
static_cast更灵活(可配合 SFINAE / concepts),std::to_underlying更简洁(仅限值转换)
最容易被忽略的一点:它只对有明确定义底层类型的枚举有效。传统无作用域枚举(enum { A };)在某些编译器下可能无法通过 std::to_underlying 编译,必须先用 std::underlying_type 推导类型再 static_cast。所以工程中优先用 enum class,并显式指定底层类型。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











