代码改变世界

c++ template(9)trait和Policy

2013-03-29 11:59  Clingingboy  阅读(1619)  评论(0编辑  收藏  举报

 

先看一个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'; 
}