【模板进阶】类模板中可变参的特殊继承方式
本篇博客主要介绍在类模板中可变参数的特殊继承方式和展开方式。 回顾之前的可变参展开:可变参模板
一、父类
首先,我们有一个父类,是一个可变参类模板,如下:
//父类
template<typename...Args>
class myclass {
public:myclass() {std::cout << "myclass::myclass()执行了,可变参个数为:" << sizeof...(Args) << "\n";}
};
下面我们开始对它的特殊继承进行讨论。
二、 m y c l a s s < A r g . . . > myclass<Arg...> myclass<Arg...>继承
参考下方代码:
//myclass<Args...>继承
template<typename... Args>
class myclass2 :public myclass<Args...> {
public:myclass2() {std::cout << "myclass2::myclass2()执行了,可变参个数为:" << sizeof...(Args) << "\n";}};
像这样的继承方式,在参数范围上与父类一样。例如,下面的代码:
myclass2<double, float, int> myc2;
将会实例化出一个 m y c l a s s < d o u b l e , f l o a t , i n t > myclass<double,float,int> myclass<double,float,int>的父类和 m y c l a s s 2 < d o u b l e , f l o a t , i n t > myclass2<double,float,int> myclass2<double,float,int>的子类。调用结果如下:
三、 m y c l a s s < A r g > . . . myclass<Arg>... myclass<Arg>...继承
这样的继承方式可以看做是多继承,具体上,这是继承的一个基类参数包,可以参考:基类参数包的展开这篇博客,讲的比较清晰。
由于是多继承,那自然会实例化出多个父类。比如下面的代码:
//myclass<Args>..继承
template<typename... Args>
class myclass3 :public myclass<Args>...{
public:myclass3() {std::cout << "myclass3::myclass3()执行了,可变参个数为:" << sizeof...(Args) << "\n";}
};
这里会实例化出 m y c l a s s < d o u b l e > , m y c l a s s < f l o a t > , m y c l a s s < i n t > myclass<double>,myclass<float>,myclass<int> myclass<double>,myclass<float>,myclass<int>三个父类模板,通过递归的方式逐步展开
myclass3<double, float, int> myc3;
可以发现,实例化出了三个父类模板,和一个子类模板:
四、 m y c l a s s < A r g , c h a r > . . . myclass<Arg,char>... myclass<Arg,char>...继承
这种继承方式和上一中类似,只不过指定了增加一个 c h a r char char类型的参数,同样会实例化出多个父类模板。
参考下面的代码:
//myclass<Arg,char>继承
template<typename... Args>
class myclass4 :public myclass<Args, char>...{
public:myclass4() {std::cout << "myclass4::myclass4()执行了,可变参个数为:" << sizeof...(Args) << "\n";}};
这将实例化出 m y c l a s s < d o u b l e , c h a r > , m y c l a s s < f l o a t , c h a r > , m y c l a s s < i n t , c h a r > myclass<double,char>,myclass<float,char>,myclass<int,char> myclass<double,char>,myclass<float,char>,myclass<int,char>三个父类,和 m y c l a s s 4 < d o u b l e , f l o a t , i n t , c h a r > myclass4<double,float,int,char> myclass4<double,float,int,char>的一个子类。
myclass4<double, float, int> myc4;
这里显示可变参数为 3 3 3不包括 c h a r char char类型,因为它不属于可变参数里面,所以实际上这里还是四个参数。
五、 m y c l a s s < A r g s , A r g s . . . > . . . myclass<Args,Args...>... myclass<Args,Args...>...继承
这种继承方式,前一个参数是 A r g s Args Args只有一个参数,而后一个参数 A r g s . . . Args... Args...是一个参数包,而最后又用一个 . . . ... ...表示继承的是参数包,因此这里会实例化出多个父类。
//myclass<Args,Args...>...继承
template<typename... Args>
class myclass5 :public myclass<Args, Args...>...{
public:myclass5() {std::cout << "myclass5::myclass5()执行了,可变参个数为:" << sizeof...(Args) << "\n";}};
下方的代码将实例化出 m y c l a s s < d o u b l e , d o u b l e , f l o a t , i n t > , m y c l a s s < f l o a t , d o u b l e , f l o a t , i n t > , m y c l a s s < i n t , d o u b l e , f l o a t , i n t > myclass<double,double,float,int>,myclass<float,double,float,int>,myclass<int,double,float,int> myclass<double,double,float,int>,myclass<float,double,float,int>,myclass<int,double,float,int>这个三个父类,和 m y c l a s s 5 < d o u b l e , f l o a t , i n t > myclass5<double,float,int> myclass5<double,float,int>这个子类
myclass5<double, float, int> myc5;
运行结果:
六、 m y c l a s s < A r g . . . , A r g . . . > myclass<Arg...,Arg...> myclass<Arg...,Arg...>继承
与第一种继承类似,只不过把参数列表复制了一遍。参考下方代码:
//myclass<Args...,Args...>继承
template<typename... Args>
class myclass6 :public myclass<Args..., Args...> {
public:myclass6() {std::cout << "myclass6::myclass6()执行了,可变参个数为:" << sizeof...(Args) << "\n";}
};
这将实例化出 m y c l a s s < d o u b l e , f l o a t , i n t , d o u b l e , f l o a t , i n t > myclass<double,float,int,double,float,int> myclass<double,float,int,double,float,int>六个参数的父类。
myclass6<double, float, int> myc6;
如图:
七、 m y c l a s s < A r g , A r g > . . . myclass<Arg,Arg>... myclass<Arg,Arg>...继承
这种继承方法和 m y c l a s s < A r g > . . . myclass<Arg>... myclass<Arg>...类似,只不过是实例化出的模板参数复制了一遍,同样也是多继承。参考下方代码:
//myclass<Args,Args,Args...>...继承
template<typename... Args>
class myclass9 :public myclass<Args,Args>...{
public:myclass9() {std::cout << "myclass9::myclass9()执行了,可变参个数为:" << sizeof...(Args) << "\n";}};
这将实例化出 m y c l a s s < d o u b l e , d o u b l e > , m y c l a s s < f l o a t , f l o a t > , m y c l a s s < i n t , i n t > myclass<double,double>,myclass<float,float>,myclass<int,int> myclass<double,double>,myclass<float,float>,myclass<int,int>这个三个父类。
myclass9<double, float, int> myc9;
如下图:
八、总结:
对于可变参类模板的继承方式总结起来就两种,其他方式可以看做是这两种方式的排列组合。
( 1 ) (1) (1)形如 t e m p l a t e < A r g s . . . > template<Args...> template<Args...>的单继承
( 2 ) (2) (2)形如 t e m p l a t e < A r g s > . . . template<Args>... template<Args>...的多继承
继承的时候可以对这两种类型进行排列组合,也可以指定增加其中一个类型,如 c h a r char char类型等。
注意, t e m p l a t e < A r g s . . . > template<Args...> template<Args...>可以有多个,而 t e m p l a t e < A r g s > . . . template<Args>... template<Args>...只能有一个。
即如下的是合法的:
t e m p l a t e < A r g s , A r g s . . . , A r g s . . . , A r g s . . . > . . . template<Args,Args...,Args...,Args...>... template<Args,Args...,Args...,Args...>...
而多继承一定要配合 A r g s Args Args来使用,即 t e m p l a t e < A r g s . . . > . . . template<Args...>... template<Args...>...是非法的!