zoukankan      html  css  js  c++  java
  • 模板与继承之艺术——命名模板参数

    一、命名模板参数
    许多模板技术拖着一长串的类型参数,不过很多参数都设有合理的缺省值。
    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,转载请注明出处。
  • 相关阅读:
    Linux 安装jdk 报错 Error: could not find libjava.so Error: Could not find Java SE Runtime Environment.
    k8s 挂载ceph rbd
    spinnaker结合表达式实现发版时下拉列表选择docker image
    istio环境集成zipkin
    istio 日志打印 request body 和respon body
    jenkins任务中无法执行sudo,管理员操作
    ansible根据shell命令返回值,判断是否应该急继续往下执行
    ReplicaSetController、ReplicationController
    kubeproxy
    PodGCController
  • 原文地址:https://www.cnblogs.com/claruarius/p/4111904.html
Copyright © 2011-2022 走看看