std::is_scoped_enum用于精准识别enum class/struct,C++23标准化,支持if constexpr分支、SFINAE约束及安全提取底层类型,不关心final、constexpr等修饰符。

std::is_scoped_enum 用来区分 enum class 和普通 enum
它只在 C++23 中标准化(此前是 GCC/Clang 的扩展),核心用途是元编程中精准识别“作用域枚举”——即 enum class 或 enum struct,而非传统无作用域的 enum。这在类型分发、SFINAE 条件选择、序列化策略或 trait 特化时很关键。
配合 if constexpr 实现编译期分支
当需要为不同枚举类型提供差异化行为(比如打印、序列化、哈希计算)时,std::is_scoped_enum_v 可直接用于 if constexpr 分支,避免运行时开销和重载歧义。
templateconstexpr auto enum_name() { if constexpr (std::is_scoped_enum_v ) { return "scoped"; } else if constexpr (std::is_enum_v ) { return "unscoped"; } else { return "not_enum"; } }
-
enum class Color { R, G };→ 返回"scoped" -
enum Dir { L, R };→ 返回"unscoped" -
int→ 返回"not_enum"
作为 SFINAE 或 requires 子句的约束条件
想只接受作用域枚举做模板参数?不能只靠 std::is_enum_v,因为它对两种枚举都返回 true。必须叠加 std::is_scoped_enum_v 排除传统 enum。
templaterequires std::is_scoped_enum_v constexpr void process_scoped_enum(E e) { /* ... */ }
-
process_scoped_enum(Color::R)✅ 编译通过 -
process_scoped_enum(Dir::L)❌ 约束失败,不参与重载决议 - 若仅用
std::is_enum_v,两者都会匹配,可能引发意料外的隐式转换或 ADL 冲突
与 std::underlying_type 配合提取底层类型更安全
传统 enum 允许隐式转为整数,而 enum class 默认禁止——但元编程中常需取其底层类型做 bit 操作或容器索引。此时先确认是 scoped enum,再取 std::underlying_type_t 更可靠:
立即学习“C++免费学习笔记(深入)”;
templateusing safe_underlying_t = std::conditional_t< std::is_scoped_enum_v , std::underlying_type_t , void >;
- 对
enum class返回真实底层类型(如int) - 对普通
enum返回void,触发编译错误,防止误用 - 比直接写
std::underlying_type_t更健壮:后者对非枚举类型直接 SFINAE 失败,但对普通 enum 却合法,容易掩盖设计意图
真正容易被忽略的是:std::is_scoped_enum 对带 final 修饰的 enum class 同样返回 true,但它不关心是否 constexpr、是否含 [[nodiscard]],也不反映是否有自定义 operator==。它的职责非常窄——只回答“这个类型是不是由 enum class 或 enum struct 定义的”。别指望它帮你判断值语义或可比性。











