如何为多参数模板类型编写单模板参数Concept约束?
首先定义了一个自定义模板类:
template<typename T1, typename T2, typename T3> class MyType{ public: using value_type = T1; value_type val() { return val; } private: T1 val; };
希望编写一个MyTypeTemplateType概念,能让如下形式的模板函数接受任意实例化后的MyType类型:
template<MyTypeTemplateType T> T myFunc(T arg){ // 示例操作 return T{std::abs(arg.val())}; };
当前的Concept实现如下:
template<typename... Ts> concept MyTypeTemplateType= requires(MyType<Ts...> arg) { arg.val(); };
但执行以下代码时:
MyType<int, float, float> myVal{5}; auto myVal2 = myFunc(myVal);
出现编译器错误:
In substitution of 'template requires MyTypeTemplateType T myFunc(T) [with T = MyType<int, float, float>]';
required for the satisfaction of 'MyTypeTemplateType' [with T = MyType<int, float, float>]
in requirements with 'MyType<Ts ...> arg' [with Ts = {int, float, float}]
wrong number of template arguments (1, should be 3)
需要将传入的具体类型T分解为MyType的模板参数包,解决这个问题。
解决方案
错误原因
当前的Concept是针对**模板参数包Ts...**定义的,它期望传入的是MyType的三个模板参数(比如int, float, float),但实际使用时传入的是已经实例化完成的具体类型MyType<int, float, float>,编译器无法将这个具体类型拆解为模板参数包去匹配MyType<Ts...>,因此报错参数数量不匹配。
正确实现方式
方式1:借助类型特征(Trait)实现
先定义一个辅助类型特征,用来判断某个类型是否是MyType的实例:
#include <type_traits> // 基础模板:默认所有类型都不是MyType template<typename T> struct is_my_type : std::false_type {}; // 特化模板:匹配所有MyType<T1,T2,T3>的实例 template<typename T1, typename T2, typename T3> struct is_my_type<MyType<T1,T2,T3>> : std::true_type {}; // 简化的变量模板,方便使用 template<typename T> constexpr bool is_my_type_v = is_my_type<T>::value;
基于这个特征编写Concept,同时可以附加成员函数的检查:
template<typename T> concept MyTypeTemplateType = is_my_type_v<T> && requires(T arg) { arg.val(); // 确保val()成员函数存在且可调用 };
此时myFunc就能正常编译运行,传入任意MyType实例都会被Concept匹配。
方式2:直接在Concept中匹配模板类型
利用C++20的模板lambda推导,直接检查类型是否是MyType的实例,无需额外定义特征:
template<typename T> concept MyTypeTemplateType = requires(T arg) { // 通过模板lambda的参数推导,判断T是否是MyType<T1,T2,T3> []<typename T1, typename T2, typename T3>(MyType<T1,T2,T3>) {} (arg); arg.val(); // 同时检查val()成员 };
这种方式更简洁,直接在Concept的约束中完成类型匹配和成员检查。
修正后的使用示例
#include <cmath> MyType<int, float, float> myVal{5}; auto myVal2 = myFunc(myVal); // 编译通过
内容的提问来源于stack exchange,提问作者Flip

