C++多模板模板参数:如何实现自动匹配内部依赖的类模板定义
可满足需求的模板实现与匹配规则说明
正确的类模板定义
直接将原模板中作为依赖的两个参数,从普通类型参数修改为模板模板参数即可,完整定义如下:
template <typename A, typename B, // 两个模板模板参数:强制传入的DepA、DepB是可接收1个类型参数的类模板 template <typename> typename DepA, template <typename> typename DepB> class aClass { // 类内部使用依赖实例时,直接将A、B传入依赖模板完成实例化即可 DepA<A> dep_a; DepB<B> dep_b; };
修改完成后,你期望的简化实例化写法可直接正常工作:
// 无需手动为vector、deque传入类型参数,编译器会自动完成类型绑定 aClass<int, double, std::vector, std::deque> instance;
模板参数位置匹配的核心逻辑
很多人对模板模板参数的传参逻辑有困惑,实际上编译器的匹配规则非常直白:
- 模板模板参数声明里写的
template <typename> typename DepA,本质是给编译器设定校验规则:传入的实参必须是一个类模板,且这个类模板至少能接收1个类型参数 - 匹配过程完全按形参的从左到右的位置顺序对应,完全不关心模板内部的参数命名:传入的类模板的第一个类型形参,会自动和你实例化aClass时传入的A类型绑定,后续位置上的形参如果有默认值,编译器会直接调用对应默认实参填充
- 以你用到的
std::vector为例:std::vector的原生模板声明其实是template <typename T, typename Allocator = std::allocator<T>> class vector,它带有2个类型形参,但因为第二个形参带默认值,完全可以匹配上我们写的“接收1个类型参数”的模板模板参数要求,编译器会自动把int绑定到T的位置,Allocator用默认值,最终生成std::vector<int>的具体类型
常见踩坑说明
- 语法版本兼容:在C11、C14标准下,模板模板参数的占位符必须使用
class而非typename,也就是要把上面的定义写成template <typename> class DepA、template <typename> class DepB,C++17之后才放开了用typename的写法,看老代码时遇到这种写法无需觉得奇怪 - 约束效果天然生效:如果传入的DepA不是“能接收1个类型参数的类模板”(比如传了个需要2个类型参数且没有默认值的模板,或者干脆传了个普通类型),编译器会直接抛出模板不匹配的编译错误,正好满足你“DepA必须可接收类型A作为模板实参”的约束要求,C++20之前的代码也可以靠这个语法天然实现类型约束
- 不要混淆普通模板参数和模板模板参数:如果还是把DepA、DepB声明为普通的
typename DepA参数,哪怕你传了std::vector进来,编译器也会把std::vector当成未实例化的模板而非具体类型,直接触发编译错误,根本无法实现自动位置匹配
内容的提问来源于stack exchange,提问作者MaPo
相关产品推荐
相关产品推荐

