c++oding="utf-8" ?>
std::is_scoped_enum是c++23引入的编译期类型特征,仅对enum class/struct返回true,用于精确区分作用域枚举与传统enum,不支持c++20及更早标准。

std::is_scoped_enum 是什么,能用来做什么
std::is_scoped_enum 是 C++23 引入的类型特性(type trait),用于在编译期判断一个类型是否为作用域枚举(即 enum class 或 enum struct)。它**不识别传统枚举(enum)**,也不识别 enum class 的底层类型(比如 int),只对枚举类型本身返回 true。它常被用在 SFINAE 或 requires 约束中,实现“仅接受作用域枚举”的模板逻辑。
在模板中用 std::is_scoped_enum 做 SFINAE 重载区分
最常见实操场景是:你希望某个函数模板只对 enum class 实例化,而拒绝 enum、整数或类类型。这时不能靠 std::is_enum_v<t></t> —— 它对两者都返回 true,必须用 std::is_scoped_enum_v<t></t>。
示例:只允许传入作用域枚举的打印函数:
template<typename t>
auto print_enum_name(T e) -> std::enable_if_t<:is_scoped_enum_v>, void> {
// 实际逻辑(比如配合反射或字符串映射)
static_assert(std::is_scoped_enum_v<t>, "T must be a scoped enum");
}</t></:is_scoped_enum_v></typename>
注意:std::enable_if_t 必须放在返回类型位置才能触发 SFINAE;若写在参数列表里(如 std::enable_if_t<...>* = nullptr</...>),也行,但返回类型方式更直观。
- 如果传入
enum class Color { Red, Green };,编译通过 - 如果传入
enum Dir { Left, Right };,编译失败(std::is_scoped_enum_v<dir></dir>为false) - 如果传入
int,同样失败,且错误信息会指向std::enable_if_t条件不满足
C++20 概念约束写法更清晰
相比 SFINAE,C++20 的 requires 更易读、错误提示更友好:
template<typename t>
concept scoped_enum = std::is_scoped_enum_v<t>;
<p>template<scoped_enum t>
void serialize(T e) {
// 只有 enum class 能进这里
}</scoped_enum></p></t></typename>
这种写法直接把约束命名出来,调试时编译器报错会明确说 “candidate template ignored: constraints not satisfied”,比 SFINAE 的“no matching function”更容易定位。
- 概念名
scoped_enum是自定义的,不与标准库冲突 - 不能写成
template<:is_scoped_enum_v>></:is_scoped_enum_v>—— 这语法非法;必须先定义 concept 或用requires子句 - 若同时需要底层类型信息(比如序列化时需知道是
uint8_t还是long),可组合std::underlying_type_t<t></t>
容易忽略的兼容性与陷阱
std::is_scoped_enum 是 C++23 特性。如果你用的是 GCC 12/Clang 15 之前的版本,或者没开 -std=c++23(或 -std=gnu++23),它根本不存在 —— 编译器会报 ‘is_scoped_enum’ is not a member of ‘std’。
- MSVC 从 19.35(VS 2022 17.5)开始支持,但需 /std:c++23
- Clang 15 默认不启用 C++23,必须显式加
-std=c++23 - 没有 C++23?可以手动模拟:作用域枚举一定满足
std::is_enum_v<t> && !std::is_convertible_v<t std::underlying_type_t>></t></t>,但这不完全可靠(某些自定义转换可能干扰),慎用 - 别和
std::is_scoped_enum_v<decltype></decltype>混淆:枚举器(enumerator)是常量,不是类型,decltype得到的是枚举类型本身,所以这个写法是对的
真正麻烦的是跨编译器 CI 配置 —— 一个地方跑得通,另一个地方因标准版本卡住,建议在 cmake 中显式检查 __cpp_lib_is_scoped_enum >= 202011L 宏。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











