std::underlying_type 是c++11引入的类型萃取模板,用于在编译期获取枚举类型的底层整型(如int、unsigned char),需显式传入枚举类型名并加::type使用,不可用于非枚举类型或非类型模板参数。
std::underlying_type 是什么,为什么不能直接用
std::underlying_type 是一个类型萃取模板,作用是从枚举类型中提取其底层整型类型(比如 int、unsigned char 等)。但它不是“获取值”的工具,而是编译期类型计算工具——你不能对它做 decltype(x) 那种运行时推导,必须显式传入一个枚举类型名。
常见错误是写成:std::underlying_type<decltype></decltype> —— 这其实可以,但前提是 my_enum_var 的类型必须是枚举(而非枚举类或退化为整数),且更稳妥的做法是直接用枚举类型名,比如 std::underlying_type<myenum></myenum>。
- 只接受枚举类型(
enum或enum class),传入int或auto会触发 SFINAE 失败或编译错误 - 返回的是一个结构体
std::underlying_type<e>::type</e>,不是类型本身,必须加::type才能使用 - C++11 起可用,但部分老编译器(如 GCC 4.7 前)对
enum class支持不全,可能报 “no member named ‘type’”
怎么正确写出 std::underlying_type::type 的等效别名
每次写 std::underlying_type<e>::type</e> 很啰嗦,推荐用 using 封装成别名。注意:不能在函数内局部定义别名来用于模板参数推导(比如作为函数返回类型),必须在命名空间或类作用域中定义。
安全写法示例:
立即学习“C++免费学习笔记(深入)”;
template <typename E> using underlying_t = typename std::underlying_type<E>::type;
这样就能写 underlying_t<myenum></myenum>,简洁且泛型友好。但要注意:
- 这个别名本身不检查
E是否为枚举——如果误传非枚举类型,错误信息会非常晦涩(例如 “‘type’ is not a member of …”) - 若想加约束,C++20 可配合
std::is_enum_v<e></e>+requires;C++17 前可用static_assert在别名内部兜底 - 别名不能用于非类型模板参数(比如
template<underlying_t> V></underlying_t>是非法的,因为underlying_t<e></e>是类型,不是值)
std::underlying_type 和 auto + static_cast 混用的坑
有人想“绕过类型萃取”,直接写 static_cast<auto>(e)</auto> —— 这在 C++20 前根本无效,auto 不能出现在 static_cast 目标类型位置。C++20 允许 static_cast<auto></auto>,但它推导的是表达式的**值类别和 cv 限定**,不是底层类型。