std::is_scoped_enum是C++23引入的特性,GCC 12/Clang 14/MSVC 19.30之前版本不支持,需通过__cpp_lib_is_scoped_enum宏检测,并可用std::is_enum_v与!std::is_convertible_v<T, int>手动模拟。

std::is_scoped_enum 在 C++23 之前不可用
别急着写 std::is_scoped_enum —— 它是 C++23 引入的,如果你用的是 GCC 12/Clang 14 之前的版本,或者 MSVC 19.30 之前,默认不支持。编译会直接报错:error: 'is_scoped_enum' is not a member of 'std'。确认标准版本最简单的方式是检查 __cpp_lib_is_scoped_enum 宏:
#if __cpp_lib_is_scoped_enum <= 202011L #error "std::is_scoped_enum not available" #endif
若不满足,得自己实现或降级使用 std::is_enum + 手动判断(见下一条)。
如何用 static_assert + std::is_scoped_enum 约束模板参数
假设你希望一个函数模板只接受 enum class,拒绝 enum 和其他类型。直接用 static_assert 最清晰:
template <typename T>
void process_enum(T) {
static_assert(std::is_scoped_enum_v<T>, "T must be a scoped enum");
// ...
}
注意三点:
立即学习“C++免费学习笔记(深入)”;
-
std::is_scoped_enum_v<T>是变量模板,比std::is_scoped_enum<T>::value更简洁 - 它对
enum class E { a, b };返回true,对enum U { x, y };返回false - 对非枚举类型(如
int、struct S {})也返回false,所以断言能拦住所有非法输入
兼容 C++17/20 的手动判定方法
如果必须支持旧标准,可以靠“scoped enum 是 enum 且不可隐式转换为整数”这一特性间接判断。但更稳妥的做法是结合 std::is_enum_v<T> 和 std::is_convertible_v<T, int>:
template <typename T> constexpr bool is_scoped_enum_v = std::is_enum_v<T> && !std::is_convertible_v<T, int>;
这个表达式在绝大多数情况下有效,但有例外:
- 如果某个
enum class显式声明了operator int(),它就变成可转换的,会被误判为非 scoped - 某些老编译器对
std::is_convertible处理不一致(尤其是涉及私有构造时),建议加static_assert验证典型用例 - 它不能区分
enum class和enum struct(二者等价),但这不是问题
为什么不能只用 std::is_enum_v?
std::is_enum_v<T> 对 enum 和 enum class 都返回 true,无法区分作用域行为。比如:
enum Legacy { A, B };
enum class Modern { X, Y };
static_assert(std::is_enum_v<Legacy>); // true
static_assert(std::is_enum_v<Modern>); // true
如果你的模板逻辑依赖强类型语义(比如禁止与整数混用、要求 ADL 查找限定名),仅靠 std::is_enum_v 就会放行 Legacy,导致后续操作出错。真正的约束点不在“是不是枚举”,而在“是不是带作用域的枚举”。
实际项目里最容易漏掉的是编译器版本检查——写了 std::is_scoped_enum 却没配 C++23 标准,或者没设 -std=c++23,结果 CI 上编译失败。先查宏,再写断言,比事后调试快得多。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/shoujipingce/126977.html