C++中如何强制模板参数为限定作用域枚举值类型?
实现限定作用域枚举值专属的类模板
实现思路
要让类模板直接接受限定作用域枚举值作为模板参数,同时约束该参数必须是限定作用域枚举的有效值,需要结合C++20的auto非类型模板参数和concept约束来实现。
步骤1:实现判断限定作用域枚举的类型 trait
首先需要一个类型 trait 来识别限定作用域枚举(scoped enum),核心判断逻辑是:类型是枚举,且不能隐式转换为其底层整数类型(这是scoped enum和unscoped enum的关键区别):
#include <type_traits> template <typename E> struct is_scoped_enum : std::false_type {}; template <typename E> requires std::is_enum_v<E> && !std::is_convertible_v<E, std::underlying_type_t<E>> struct is_scoped_enum<E> : std::true_type {}; template <typename E> constexpr bool is_scoped_enum_v = is_scoped_enum<E>::value;
步骤2:定义约束非类型参数的concept
接下来定义一个concept,用来约束非类型模板参数的类型必须是限定作用域枚举:
template <auto Val> concept ScopedEnumValue = is_scoped_enum_v<std::decay_t<decltype(Val)>>;
步骤3:编写目标形式的类模板
现在就可以写出你想要的类模板形式,直接用受约束的auto非类型参数作为模板参数:
template <ScopedEnumValue T> class Bar {};
使用示例
当你需要使用Bar时,直接传入限定作用域枚举的具体值即可:
// 定义一个限定作用域枚举 enum class MyScopedEnum { Option1, Option2 }; // 合法:传入的是限定作用域枚举值 Bar<MyScopedEnum::Option1> valid_bar; // 非法:传入非限定作用域枚举或普通值会触发编译错误 enum UnscopedEnum { A, B }; // Bar<UnscopedEnum::A> invalid_bar1; // 编译失败 // Bar<123> invalid_bar2; // 编译失败
说明
- 该实现依赖C++20标准,因为用到了
auto非类型模板参数和concept特性。 - 相比你之前的双参数模板写法,这种方式更简洁,直接将枚举值作为模板参数,同时自动约束其类型为限定作用域枚举,不需要手动指定枚举类型。
内容的提问来源于stack exchange,提问作者Omer Kawaz
相关产品推荐
相关产品推荐

