模板与继承之艺术——命名模板参数
一、命名模板参数
许多模板技术拖着一长串的类型参数,不过很多参数都设有合理的缺省值。
template<typename Policy1 = DefaultPolicy1,
typename Policy2 = DefaultPolicy2,
typename Policy3 = DefaultPolicy3,
typename Policy4 = DefaultPolicy4>
class BreadSlicer{};
但是如果我们需要指定某个非缺省实参,还必须明确的指定在它之前的所有实参,即使这些实参跟默认参数一致。
BreadSlicer<DefaultPolicy1, DefaultPolicy2, Custom>
如果我们能够实现类似BreadSlicer<Policy3 = Custom>显然更有效率。
思路是这样的:
(1)将参数分派给一个叫做Policy3的东西管理,上面的“=”可以换成模板,将Custom作为模板实参传递进去。
这里我们将Policy3换个名字Policy3_is,然后用Policy3_is<Custom>实现赋值。
(2)将默认实参合并在一起,并用新名字进行索引修改。
class DeafultPolicies{
public:
typedef DefaultPolicy1 P1;//DefaultPolicy1是具体类,P1是为了索引到该类型
typedef DefaultPolicy2 P2;
typedef DefaultPolicy3 P3;
typedef DefaultPolicy4 P4;
};
然后创建类似Policy3_is类进行管理。
template<typename Policy>
class Policy1_is : virtual public DefaultPolicies{ //为什么要虚继承?待会揭晓
typedef Policy P1; //将P1从新赋值
};
template<typename Policy>
class Policy2_is : virtual public DefaultPolicies{
typedef Policy P2;
};
。。。//剩下的Policy3_is与Policy4_is类似
上面的四个类可以说是修改器,那这些修改器要怎样安装,安装到哪里呢?要创建一个有四个“插槽”的“插座”。
在这之前首先解决一个问题,默认参数是什么,根据上面的模式,默认参数应该也从DefaultPolicies继承而来的。
class DefaultPolicyArgs : virtual public DefaultPolicies{};//默认实参
”插槽“在插入“修改器”之前应该是被默认实参占领所以,要将四个相同类型(默认实参)同时继承到一个类里面就需要使用一点小技巧。
template<typename Base, int D> //使用D将相同的类型编程不同类型,但是类的本质不变,还是子类继承基类
class D : public Base{};
template<typename T1, typename T2, typename T3, typename T4>
class PolicySelector : public D<T1, 1>, public D<T2, 2>, public D<T3, 3>, public D<T4, 4>{};
此处需要多重继承所以为了避免产生二义性,前面的“修改器”和默认参数都需要虚继承
最后就是组装默认参数。
template<typename PolicySetter1 = DefaultPolicyArgs,
typename PolicySetter2 = DefaultPolicyArgs,
typename PolicySetter3 = DefaultPolicyArgs,
typename PolicySetter4 = DefaultPolicyArgs>
class BreadSlicer{
typedef PolicySelector<PolicySetter1, PolicySetter2, PolicySetter3, PolicySetter4> Policies;
//使用Policies::P1索引第一个实参。
};
就可以直接BreadSlicer<Policy3_is<Custom> > bc;
下面是一个完整的例子。
#include <iostream>
#include <list>
using namespace std;
class DefaultPolicy1{};
class DefaultPolicy2{};
class DefaultPolicy3{
public:
void print()
{
cout << "我是默认参数3" << endl;
}
};
class DefaultPolicy4{};
class DefaultPolicies{ //将默认实参合并
public:
typedef DefaultPolicy1 P1;
typedef DefaultPolicy2 P2;
typedef DefaultPolicy3 P3;
typedef DefaultPolicy4 P4;
};
class DefaultPolicyArgs : virtual public DefaultPolicies{};
template <typename Policy>
class Policy1_is : virtual public DefaultPolicies{
public:
typedef Policy P1;
};
template<typename Policy>
class Policy2_is : virtual public DefaultPolicies{
public:
typedef Policy P2;
};
template<typename Policy>
class Policy3_is : virtual public DefaultPolicies{
public:
typedef Policy P3;
};
template<typename Policy>
class Policy4_is : virtual public DefaultPolicies{
public:
typedef Policy P4;
};
template<typename Base, int d>
class D : public Base{};
template<typename B1, typename B2, typename B3, typename B4>
class Selector : public D<B1, 1>, public D<B2, 2>, public D<B3, 3>, public D<B4, 4>{};
template <typename T1 = DefaultPolicyArgs,
typename T2 = DefaultPolicyArgs,
typename T3 = DefaultPolicyArgs,
typename T4 = DefaultPolicyArgs>
class BreadSlicer{
typedef Selector<T1, T2, T3, T4> Policies;
public:
void print(){
typename Policies::P3 p3; //使用其中一个参数类型的例子,
//就用的第三个参数来展示吧
p3.print();
}
};
class Print3{
public:
void print()
{
cout << "我是客户参数3" << endl;
}
};
int main()
{
//BreadSlicer<> b;
BreadSlicer<Policy3_is<Print3> > b;
b.print();
return 0;
}
编辑整理:Claruarius,转载请注明出处。