std::is_scoped_enum 是 c++23 引入的类型特征,仅对 enum class/enum struct 定义的作用域枚举返回 true,不关心底层类型或值;它严格区分作用域与非作用域枚举,是 std::is_enum 的真子集,定义于 中。

std::is_scoped_enum 是什么,能判断哪些类型
std::is_scoped_enum 是 C++23 引入的类型特征(type trait),用于**精确识别是否为作用域枚举(scoped enum)**,即用 enum class 或 enum struct 定义的枚举。它对 enum(非作用域枚举)、int、class、enum class 的别名(如 using E = enum class {...};)等,返回值严格不同。
关键点:它不关心枚举是否有底层类型、是否为空、是否含 constexpr 值——只看定义语法是否带 class 或 struct 关键字。
常见误判场景:
-
enum Color { red, green };→std::is_scoped_enum_v<color></color>为false(正确) -
enum class Status : uint8_t { ok, err };→true(即使有底层类型) -
template<typename t> using is_scoped = std::is_scoped_enum<t>;</t></typename>→ 别名模板不影响结果,仍按原类型判断
在 SFINAE 和 constexpr if 中怎么安全使用
由于 std::is_scoped_enum 是编译期常量表达式,它天然适合做模板约束和分支分发。但要注意:它不能直接用于函数重载解析的“唯一差异”,因为非作用域枚举也满足 std::is_enum,容易产生歧义。
推荐写法(C++17 起):
template<typename t>
constexpr auto get_enum_name() {
if constexpr (std::is_scoped_enum_v<t>) {
return "scoped";
} else if constexpr (std::is_enum_v<t>) {
return "unscoped";
} else {
return "not enum";
}
}</t></t></typename>
错误写法示例(导致硬错误):
// ❌ 错误:没有 fallback,T 不是 enum 时 static_assert 失败
template<typename t>
auto bad_overload() -> std::enable_if_t<:is_scoped_enum_v>, int> { return 1; }</:is_scoped_enum_v></typename>
正确替代(SFINAE 安全):
template<typename t std::enable_if_t>, int> = 0>
int good_overload() { return 1; }</typename>
为什么 std::is_scoped_enum_v 在 C++20 模式下可能编译失败
如果你用的是 GCC/Clang 并启用了 -std=c++20(而非 c++23),std::is_scoped_enum 将不可用——它不是 C++20 特性,而是 C++23 标准库新增项。
验证方式:
- 检查标准版本:
__cplusplus宏需 ≥202302L - 头文件无需额外包含,它定义在
<type_traits></type_traits>中(C++23 起) - MSVC 19.35+、GCC 13+、Clang 16+ 才完整支持
兼容旧标准的临时方案(不推荐长期用):
#if __cpp_lib_is_scoped_enum inline constexpr bool is_scoped_enum_v = false; } #endif
但注意:这种手动特化无法真正检测作用域枚举,仅避免编译失败;真实逻辑仍需升级工具链。
和 std::is_enum 的关系与组合使用场景
std::is_scoped_enum_v<t></t> 是 std::is_enum_v<t></t> 的真子集:所有作用域枚举都是枚举,但反之不成立。两者组合可区分三类类型:
-
std::is_scoped_enum_v<t></t>→true:必须是enum class/enum struct -
!std::is_scoped_enum_v<t> && std::is_enum_v<t></t></t>→ 非作用域枚举(传统enum) -
!std::is_enum_v<t></t>→ 其他任意类型
典型用途:序列化库中决定是否自动添加作用域前缀(如 Status::ok vs ok),或反射系统中生成枚举元信息时跳过非作用域枚举的隐式整型转换风险。
注意:不要用 std::is_scoped_enum 替代 std::underlying_type——它不提供底层类型信息,也不反映是否可隐式转为整数。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











