• c++ template(9)trait和Policy


    先看一个Demo:

    累加序列:

    template <typename T> 
    inline 
        T accum (T const* beg, T const* end) 
    { 
        T total = T();  // assume T() actually creates a zero value 
        while (beg != end) { 
            total += *beg; 
            ++beg; 
        } 
        return total; 
    } 
    

    使用示例:

    int main() 
    {
        // create array of 5 integer values 
        int num[]={1,2,3,4,5}; 
    
        // print average value 
        std::cout << "the average value of the integer values is " 
            << accum(&num[0], &num[5]) / 5 
            << '\n'; 
    
        // create array of character values 
        char name[] = "templates"; 
        int length = sizeof(name)-1; 
    
        // (try to) print average character value 
        std::cout << "the average value of the characters in \"" 
            << name << "\" is " 
            << accum(&name[0], &name[length]) / length 
            << '\n'; 
    
        return 1;
    
    }
    

    结果:

    image

    显然char的类型有问题,变量total 应该转化为int

    修改方案则是新加一个模版参数:

    template <typename T,typename V=int> 
    inline 
        V accum (T const* beg, T const* end) 
    { 
        V total = V();  // assume T() actually creates a zero value 
        while (beg != end) { 
            total += *beg; 
            ++beg; 
        } 
        return total; 
    } 
    

    同时添加了使用成本

    accum<char,int>(&name[0], &name[length])
    

    模版的trait力量:将动态模版参数定义到外部结构中

    template<typename T> 
    class AccumulationTraits; 
    
    template<> 
    class AccumulationTraits<char> { 
    public: 
        typedef int AccT; 
    }; 
    
    template<> 
    class AccumulationTraits<short> { 
    public: 
        typedef int AccT; 
    }; 
    
    template<> 
    class AccumulationTraits<int> { 
    public: 
        typedef long AccT; 
    }; 
    
    template<> 
    class AccumulationTraits<unsigned int> { 
    public: 
        typedef unsigned long AccT; 
    }; 
    
    template<> 
    class AccumulationTraits<float> { 
    public: 
        typedef double AccT; 
    }; 
    
    template <typename T> 
    inline 
        typename AccumulationTraits<T>::AccT accum (T const* beg, 
        T const* end) 
    { 
        // return type is traits of the element type 
        typedef typename AccumulationTraits<T>::AccT AccT; 
    
        AccT total = AccT();  // assume T() actually creates a zero value 
        while (beg != end) { 
            total += *beg; 
            ++beg; 
        } 
        return total; 
    } 
    

    现在可以保持调用方式保持不变,通过trait来更改类型参数

    accum(&name[0], &name[length])
    

    现在结果是正确的

    image

    trait的默认值

    trait类型的初始值用构造函数初始化可能会有问题,所以可以再次用trait来定义默认值

    默认值方式:1.静态变量(只能整型数值和枚举),2.静态方法(推荐)

    template<> 
    class AccumulationTraits<char> { 
    public: 
        typedef int AccT; 
        //static AccT const zero = 0; 
        static AccT zero() { 
            return 0; 
        } 
    
    }; 
    

    更改后的初始化方式:

    template <typename T> 
    inline 
        typename AccumulationTraits<T>::AccT accum (T const* beg, 
        T const* end) 
    { 
        // return type is traits of the element type 
        typedef typename AccumulationTraits<T>::AccT AccT; 
    
        AccT total = AccumulationTraits<T>::zero();
        while (beg != end) { 
            total += *beg; 
            ++beg; 
        } 
        return total; 
    } 
    

    This is the key of the traits concept: Traits provide an avenue to configure concrete elements (mostly types) for generic computations.

    trait参数化

    有时候我们想改变通过trait本身的默认模版参数,这样就需要对trait本事做一个参数封装

    封装一个默认的模版参数

    template <typename T, 
        typename AT = AccumulationTraits<T> > 
    class Accum { 
    public: 
        static typename AT::AccT accum (T const* beg, T const* end) { 
            typename AT::AccT total = AT::zero(); 
            while (beg != end) { 
                total += *beg; 
                ++beg; 
            } 
            return total; 
        } 
    }; 
    

    1

    现在之前的方法应该如下示例:

    template <typename T> 
    inline 
        typename AccumulationTraits<T>::AccT accum (T const* beg, 
        T const* end) 
    { 
        return Accum<T>::accum(beg, end); 
    } 
    
    

    trait参数化

    template <typename Traits, typename T> 
    inline 
        typename Traits::AccT accum (T const* beg, T const* end) 
    { 
        return Accum<T, Traits>::accum(beg, end); 
    } 
    

    Policy

    Policy注重算法,如下示例:Policy是一个静态类,通过动态编译来计算

    template <typename T, 
        typename Policy = SumPolicy, 
        typename Traits = AccumulationTraits<T> > 
    class Accum { 
    public: 
        typedef typename Traits::AccT AccT; 
        static AccT accum (T const* beg, T const* end) { 
            AccT total = Traits::zero(); 
            while (beg != end) { 
                Policy::accumulate(total, *beg); 
                ++beg; 
            } 
            return total; 
        } 
    }; 
    

    不同Policy算法

    class SumPolicy { 
    public: 
        template<typename T1, typename T2> 
        static void accumulate (T1& total, T const & value) { 
            total += value; 
        } 
    }; 
    
    class MultPolicy { 
    public: 
        template<typename T1, typename T2> 
        static void accumulate (T1& total, T const& value) { 
            total *= value; 
        } 
    }; 
    

    使用示例:

    int main() 
    { 
        // create array of 5 integer values 
        int num[]={1,2,3,4,5}; 
    
        // print product of all values 
        std::cout << "the product of the integer values is " 
            << Accum<int,MultPolicy>::accum(&num[0], &num[5]) 
            << '\n'; 
    } 
    
  • 相关阅读:
    b_jd_水坑数量(向外流dfs)
    b_wy_购买商品使得满减最省(01背包)
    b_wy_最优路径(构造树+dfs)
    Redis:List列表相关指令
    Redis:String字符串常用指令
    Redis:linux基本的指令
    Redis:redis-benchmark性能测试/压力测试
    Redis:增大并发量的演进过程
    Kafka的下载安装和测试,及消费端数据中文乱码问题
    Git:常用命令
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/2988604.html
Copyright © 2020-2023  润新知