类模板参数展开
看一个可变参类模板的范例。先写一个可变参类模板的偏特化
template<typename First, typename... Others>
class myclasst<First, Others...> : private myclasst<Others...> //偏特化
{
}
注意观察上面的代码,观察继承的是谁,模板参数也是分开成一个和一包,这种写法比较固定。
如果此时编译,会报错,因此会写一个泛化版本的类模板,然后才能写特化版本的类模板。所以,在上面代码面前添加代码:
template<typename ...Args>
class myclasst
{
public:
myclasst()
{
printf("myclasst::myclasst()泛化版本执行了,this = %p\n", this);
}
};
现在编译就不会报错了,实际上也有人这样写:
template<typename ...Args> class myclasst;
这里是只写类模板的声明而不写成类模板定义。
现在继续改造上面的可变参类模板的偏特化写法,在其中增加构造函数以及一个成员变量:
template<typename First, typename... Others>
class myclasst<First, Others...> : private myclasst<Others...> //偏特化
{
public:
myclasst() :m_i(0)
{
printf("myclasst::myclasst()偏特化版本执行了,this = %p,sizeof...(Others)=%d\n",
this, sizeof...(Others));
}
}
然后改造下主模板的定义,也加入一个构造函数:
template<typename ...Args>
class myclasst
{
public:
myclasst()
{
printf("myclasst::myclasst()泛化版本执行了,this = %p\n", this);
}
};
在main函数中添加代码:
myclass<int,flaot,double>myc;
运行程序如下:
myclasst<>::myclasst()特殊的特化版本执行了,this = 010FFE70
myclasst::myclasst()偏特化版本执行了,this = 010FFE70,sizeof...(Others)=0
myclasst::myclasst()偏特化版本执行了,this = 010FFE70,sizeof...(Others)=1
myclasst::myclasst()偏特化版本执行了,this = 010FFE70,sizeof...(Others)=2
这里执行了4个构造函数,系统实例化出了4个类,先来说其中3个类,因为源码分析不难。
执行代码myclass<int,flaot,double>myc;时,系统会去实例化3个类型模板参数的类模板,根据写法class myclasst<First, Others...> : private myclasst<Others...>,他继承的是两个类型模板参数的类模板,而两个类型模板参数的类模板继承的是一个类型模板参数的类模板,因此,系统首先会实例化带一个类型模板参数的类模板,然后实例化带两个类型模板参数的类模板,最后实例化带3个类型模板参数。
结合刚才的程序的运行结果,编译器遇到带0个模板参数的类模板的时候,就停止类模板参数的继承,同时带0个模板参数的类模板,就停止类模板的继承,同时,这种带0个模板参数的类模板是通过myclass的泛化版本实例化的。
完整代码:
namespace _nmsp5
{
//主模板定义(泛化版本的类模板)
template<typename ...Args>
class myclasst
{
public:
myclasst()
{
printf("myclasst::myclasst()泛化版本执行了,this = %p\n", this);
}
};
template<> class myclasst<> //一个特殊的特化版本
{
public:
myclasst()
{
printf("myclasst<>::myclasst()特殊的特化版本执行了,this = %p\n", this);
}
};
template<typename First, typename... Others>
class myclasst<First, Others...> : private myclasst<Others...> //偏特化
{
public:
myclasst() :m_i(0)
{
printf("myclasst::myclasst()偏特化版本执行了,this = %p,sizeof...(Others)=%d\n", this, sizeof...(Others));
}
//注意这第二个参数,这一包东西的写法
myclasst(First parf, Others... paro) :m_i(parf), myclasst<Others...>(paro...)
{
cout << "-----------------begin------------------" << endl;
printf("myclasst::myclasst(parf,...paro)执行了,this = %p\n", this);
cout << "m_i = " << m_i << endl;
cout << "-----------------end------------------" << endl;
}
First m_i;
};
}