首页 > 代码库 > 模板与继承之艺术——命名模板参数

模板与继承之艺术——命名模板参数

一、命名模板参数
许多模板技术拖着一长串的类型参数,不过很多参数都设有合理的缺省值。
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,转载请注明出处。

模板与继承之艺术——命名模板参数