zoukankan      html  css  js  c++  java
  • Step By Step(C++模板Policy)

    一、Policy类:

        该篇博客中的代码示例将承接上一篇博客(C++模板Trait)中给出的累加器的例子。在之前的代码中,我们都是让累加器完成固定的累加行为,即累加求和。然而事实上,我们仍然可以修改该函数的累加算法,比如将求和算法改为求积算法。或者说,如果参数类型是字符的话,我们也可以通过该函数进行指定形式的字符连接。在实际的代码修改中,我们只需将total += *begin代码行替换为我们为该函数指定的Policy模板参数,这样我们就将该模板参数称为该函数累加过程的一个Policy。见如下代码示例和关键性注释:

     1     #include <stdio.h>
     2     
     3     template<typename T>
     4     class AccumulationTraits;
     5     
     6     template<>
     7     class AccumulationTraits<char> {
     8     public:
     9         typedef int AccT;
    10         static AccT zero() { return 0; }
    11     };
    12     
    13     template<>
    14     class AccumulationTraits<short> {
    15     public:
    16         typedef int AccT;
    17         static AccT zero() { return 0; }
    18     };
    19     
    20     template<>
    21     class AccumulationTraits<int> {
    22     public:
    23         typedef long long AccT;
    24         static AccT zero() { return 0; }
    25     };
    26     
    27     template<>
    28     class AccumulationTraits<unsigned int> {
    29     public:
    30         typedef unsigned long long AccT;
    31         static AccT zero() { return 0; }
    32     };
    33     
    34     template<>
    35     class AccumulationTraits<float> {
    36     public:
    37         typedef double AccT;
    38         static AccT zero() { return 0; }
    39     };
    40     
    41     class SumPolicy {
    42     public:
    43         template<typename T1,typename T2>
    44         static void accumulate(T1& total, T2 const& value) {
    45             total += value;
    46         }
    47     };
    48     
    49     class MultiPolicy {
    50     public:
    51         template<typename T1,typename T2>
    52         static void accumulate(T1& total, T2 const& value) {
    53             total *= value;
    54         }
    55     };
    56     
    57     template<typename T, typename Policy = SumPolicy, typename Traits = AccumulationTraits<T> >
    58     class Accum {
    59     public:
    60         typedef typename Traits::AccT AccT;
    61         static AccT accumulate(T const* begin, T const* end) {
    62             AccT total = Traits::zero();
    63             while (begin != end) {
    64                 Policy::accumulate(total,*begin);
    65                 ++begin;
    66             }
    67             return total;
    68         }
    69     };
    70     
    71     int main() {
    72         int test[5] = {1,2,3,4,5};
    73         int r = Accum<int,MultiPolicy>::accumulate(test,test + 5);
    74         printf("r is %d.",r);
    75         return 0;
    76     }
    77     //r is 0.

        这里之所以结果为0,是因为Traits类AccumulationTraits<int>::zero()方法返回的值是0。通过这个示例,可以让我们清楚的认识到,是组合使用Traits和Policy的时候,应该讲更多的细节问题考虑进来。
        
    二、Traits和Policy的主要差别:

        以下为Trait的特征和适用场景:
        1. Trait表述了模板参数的一些自然的额外属性。
        2. Trait可以是固定Trait,也就是说, 不需要通过模板参数进行传递。
        3. Trait参数通常都具有很自然的缺省值,该缺省值很少会被改写,或者说是根本就不能被改写。
        4. Trait参数可以紧密依赖于一个或多个主参数。
        5. Trait通常都是用Trait模板来实现的。
        
        下面是Policy的特征和应用场景:
        1. Policy表述了泛型函数和泛型类的一些可配置行为。
        2. 如果不以模板参数的形式进行传递的话,Policy Class几乎不起作用。
        3. Policy参数并不需要具有缺省值,而且通常都是显示指定这个参数,尽管许多泛型组件都配置了使用频率很高的缺省Policy。
        4. Policy参数和属于同一个模板的其他参数通常都是正交的。
        5. Policy class一般都包含了成员函数。
        6. Policy即可以用普通类来实现,也可以用模板类来实现。
        
    三、用模板的模板参数来实现Policy Class:

        上面的示例只是使用普通类的模板成员函数来表示Policy的,而这里我们使用模板类来重新设计这个Policy class。见如下代码片段和关键性注释:

     1     template<typename T1,typename T2>
     2     class SumPolicy {
     3     public:
     4         static void accumulate(T1& total, T2 const& value) {
     5             total += value;
     6         }
     7     };
     8     
     9     template<typename T1,typename T2>
    10     class MultiPolicy {
    11     public:
    12         static void accumulate(T1& total, T2 const& value) {
    13             total *= value;
    14         }
    15     };
    16     //这里已经将第二个模板参数定义为模板类类型,其中该模板类本身要有两个模板参数,即返回值类型和元素类型。
    17     template<typename T, 
    18              template<typename,typename> class Policy = SumPolicy, 
    19              typename Traits = AccumulationTraits<T> >
    20     class Accum {
    21     public:
    22         typedef typename Traits::AccT AccT;
    23         static AccT accumulate(T const* begin, T const* end) {
    24             AccT total = Traits::zero();
    25             while (begin != end) {
    26                 Policy<AccT,T>::accumulate(total,*begin);
    27                 ++begin;
    28             }
    29             return total;
    30         }
    31     };
    32     
    33     int main() {
    34         int test[5] = {1,2,3,4,5};        
    35         int r = Accum<int,MultiPolicy>::accumulate(test,test + 5);
    36         printf("r is %d.",r);
    37         return 0;
    38     }
    39     //r is 0.

    四、类型函数:

        对于普通函数而言,我们可以将其称为值函数,既函数接收的是某些值,同时返回结果也是值。但是对于类型函数则有些不同,他们一般接收的参数是类型实参,同时也会生成一个类型或常量作为返回的结果。下面是一个简单的类型函数的示例,主要行为是通过类型函数实现sizeof的功能。

     1     #include <stdio.h>
     2     #include <iostream>
     3     
     4     using namespace std;
     5     
     6     template<typename T>
     7     class TypeSize {
     8     public:
     9         static size_t const value = sizeof(T);
    10     };
    11     
    12     int main() {
    13         cout << "TypeSize<int>::value = " << TypeSize<int>::value << endl;
    14         return 0;
    15     }
    16     //TypeSize<int>::value = 4

        从上例可以看出,所谓的类型函数并不局限于函数本身,也可以用模板类来实现。下面将给出一个更为实用的应用场景。比如,我们的函数参数是一个容器类型,该类型为模板参数,而该函数的功能是遍历容器并返回所有元素的累加之和,该返回值的类型则需要视容器元素的类型而定,这里我们先给出一个普通的实现方式,如:

    1     template<typename ElementT, typename ContainerT>
    2     ElementT sumOfElements(ContainerT const& c) {
    3         ElementT total = ElementT();
    4         ContainerT::const_iterator it = c.begin();
    5         for (; it != c.end(); ++it)
    6             total += *it;
    7         return total;            
    8     }

        在上面的例子中,我们声明的函数必须同时提供两个模板参数,既容器类型和容器元素类型的模板参数。通过类型函数,我们可以只为该函数声明一个模板参数便可,既只有容器类型的类型参数。见如下代码和关键性注释:

     1     #include <stdio.h>
     2     #include <vector>
     3     #include <list>
     4     #include <stack>
     5     #include <typeinfo>
     6     #include <iostream>
     7     #include <conio.h>
     8     
     9     using namespace std;
    10     
    11     template<typename T>
    12     class ElementT;       //基本模板,缺省情况下不需要提供定义。
    13     
    14     template<typename T>
    15     class ElementT<vector<T> > {  //基于vector的特化
    16     public:
    17         typedef T Type;
    18     };
    19     
    20     template<typename T>
    21     class ElementT<list<T> > {    //基于list的特化
    22     public:
    23         typedef T Type;
    24     };
    25     
    26     template<typename T>
    27     class ElementT<stack<T> > {   //基于stack的特化
    28     public:
    29         typedef T Type;
    30     };
    31     
    32     template<typename T>
    33     void printElementType(T const& c) { //一个普通的测试方法,用于测试上面的类型函数。
    34         cout << "Container of " << typeid(typename ElementT<T>::Type).name() 
    35              << " elements.\n";
    36     }
    37     //在这里我们可以看到,sumOfElement只有一个模板参数了,而另一个类型参数,既元素的
    38     //的类型,我们已经通过类型函数获取到了。    
    39     template<typename C>
    40     typename ElementT<C>::Type sumOfElement(C const& c) {
    41         typedef typename ElementT<C>::Type Type;
    42         Type total = Type();
    43         C::const_iterator it = c.begin();
    44         for (; it != c.end(); ++it)
    45             total += *it;
    46         return total;
    47     }
    48     
    49     int main() {
    50         stack<bool> s;
    51         printElementType(s);
    52         vector<int> v;
    53         v.push_back(1);
    54         v.push_back(3);
    55         v.push_back(5);
    56         v.push_back(7);
    57         v.push_back(9);
    58         int r = sumOfElement(v);
    59         printf("The result of sumOfElement is %d.",r);
    60         getch();
    61         return 0;
    62     }
    63     //Container of bool elements.
    64     //The result of sumOfElement is 25.
  • 相关阅读:
    浮动广告
    jQuery给table添加行和删除行
    oracle优化方式和sql标准
    使用JavaScript中的ActiveXObject填充并设置Excel格
    打印相关的js
    利用js导出Excel
    Oracle左外连接和右外连接的写法
    天气预报抓取的方法和源代码(包括从IP获取)
    algorithm
    ungetc
  • 原文地址:https://www.cnblogs.com/orangeform/p/2635628.html
Copyright © 2011-2022 走看看