Step By Step(C++模板Policy)

[来源] 达内    [编辑] 达内   [时间]2012-09-13

该篇博客中的代码示例将承接上一篇博客(C++模板Trait)中给出的累加器的例子。

一、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 TraitsT AccT; 61         static
 AccT accumulate(T const* begin, T const
* end) { 62
             AccT total =

 Traits::zero(); 63             while
 (begin != end) { 64
                 Policyumulate(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>umulate(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 TraitsT AccT; 23         static
 AccT accumulate(T const* begin, T const
* end) { 24
             AccT total =

 Traits::zero(); 25             while
 (begin != end) { 26
                 Policy<AccT,T>umulate(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>umulate(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
         ContainerTonst_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
         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.

资源下载