跟我学c++高级篇——模板元编程之三Policy

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

一、Policy

Policy策略要把它和设计模式中的策略Strategy区分开来前者更倾向于编译期而后者则是一种设计的框架模式在上层应用设计中使用。 另外就是trait和policy这两个概念前者是用来描述类型而后者用来描述行为有点类似于属性和方法。
Policy是一种策略具体到实际就是一种具体的操作行为这个比较容易理解比如下棋采用双炮还是双车这就是一种策略。但是在实际使用中又会把Policy进行分组和抽象那就是Policies和Policy Classes。

二、Policies和Policy Classes

Policies是面向语法的而Policy是一种定义常见的普通类接口是面向方法签名的。这样理解就清楚了这种定义方式如果是英文为母语或者十分了解英文的会发现理解上更清晰透彻中文却不好翻译。Policy Classes策略类别或者说策略组合而实现了多个策略的Class又叫做hosts 或host classes。
一个policy可以实现多种policy classes只要符合策略的接口即可。而在实际的应用中可以用普通类做为Policy也可以用模板为Policy其实后者只是前者的更深一层的抽象。每个Policy对象都可以在实际编程中理解成为类和对象的关系这样基本上就把这些基本的概念搞清楚了。
1、普通类做为Policy

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

2、抽象为模板的Policy

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

3、分析说明
这里要区分开Policy模板和Policy对象模板前者指应用策略的模板而后者表示实现策略的对象的模板一个用一个是生产。只要理解了基础的应用再理解这些就好理解了不用死记硬背。
通过上面的不断分析解剖到现在应该基本明白什么是策略了即在模板中控制其具体行为的参数就是Policy。

  • 更详尽的说明参看《c++Templates全览》 侯捷@译 和《Modern c++ Design》

三、例程

理解了策略就可以在这个基础上进行“policy-based class”设计了。其实这种具体的设计就和设计模式中的策略类似了通过策略来控制行为的选择。
下面看一个例子

//普通类
#include <iostream>

template<typename T>
class AccumulationTraits;

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

template<>
class AccumulationTraits<short>
{
public:
    typedef int AccT;
    static AccT zero()
    {
        return 0;
    }
};

template<>
class AccumulationTraits<int>
{
public:
    typedef long AccT;
    static AccT zero()
    {
        return 0;
    }
};

template<>
class AccumulationTraits<unsigned int>
{
public:
    typedef unsigned long AccT;
    static AccT zero()
    {
        return 0;
    }
};

template<>
class AccumulationTraits<float>
{
public:
    typedef double AccT;
    static AccT zero()
    {
        return 0;
    }
};
//...

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

template <typename T,
    typename Policy = SumPolicy,
    typename Traits = AccumulationTraits<T> >
    class Accum {
    public:
        typedef typename Traits::AccT AccT;
        //使用默认值来处理乘法结果为0为题这是一种解决方案
        static AccT accum(T const* beg, T const* end,int init = 1)
        {
            AccT total = init?init:Traits::zero();
            while (beg != end)
            {
                Policy::accumulate(total, * beg);
                ++beg;
            }
            return total;
        }
};

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

void TestAccum()
{
    int num[] = {1,2,3,4,5};
    std::cout << "all value is:" << Accum<int>::accum(&num[0], &num[5],0) << std::endl;
    std::cout << "all mult value is:" << Accum<int, MultPolicy>::accum(&num[0], &num[5]) << std::endl;
}
int  main()
{
    TestAccum();
    return 0;
}

此处主要是对Accum中计算时增加了一个判断否则初始化的zero选择零在乘法时可能会产生非预想的结果。
那么既然如此是不是可以象上面提到的一样把其抽象化以后继续使用呢

//模板类
#include <iostream>
template <typename T1, typename T2>
class SumPolicy {
public:
    static void accumulate(T1& total, T2 const& value) {
        total += value;
    }
};


template<typename T>
class AccumulationTraits;

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

template<>
class AccumulationTraits<short>
{
public:
    typedef int AccT;
    static AccT zero()
    {
        return 0;
    }
};

template<>
class AccumulationTraits<int>
{
public:
    typedef long AccT;
    static AccT zero()
    {
        return 0;
    }
};

template<>
class AccumulationTraits<unsigned int>
{
public:
    typedef unsigned long AccT;
    static AccT zero()
    {
        return 0;
    }
};

template<>
class AccumulationTraits<float>
{
public:
    typedef double AccT;
    static AccT zero()
    {
        return 0;
    }
};

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


template <typename T,
    template<typename, typename> class 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<AccT, T>::accumulate(total, * beg);
                ++beg;
            }
            return total;
        }
};
void TestTAccum()
{
    // 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<int>::accum(&num[0], &num[5]) / 5
        << '\n';

    // print product of all values
    std::cout << "the product of the integer values is "
        << Accum<int, MultPolicy>::accum(&num[0], &num[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<char>::accum(&name[0], &name[length]) / length
        << '\n';
}
int  main()
{
    TestTAccum();
    return 0;
}

另外还可以通过偏特化的方式来支持自动的选择执行条件

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

template<>
class SumPolicy<false> {
public:
    template<typename T1, typename T2>
    static void accumulate(T1& total, T2 const& value) {
        total = total + value;
    }
};
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;
        }
};

上面的代码比较老条件分支在编译期控制也可以在c++17中使用constexpr这个在前面分析这里不重复。同时此处涉及到了“模板的模板参数”这个回头会专门进行分析说明此处先空中掠过。另外等以后会专门开辟一篇文章来写一个c++11以后的Policy的应用。

四、总结

Policy是一种个体的Action的抽象或者说算法实现的抽象。对学编程的人来说程序就是算法加数据结构。从某种意义上讲它其实是算法实现组装的一个重要手段。把共性的算法行为形成Policy再为设计所使用其实就是设计的依赖于抽象而不依赖于实现。策略是个好的手段能用好才能发挥出它更大的威力来。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: c++