一、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
二、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.
原文链接: https://www.cnblogs.com/orangeform/archive/2012/09/07/2635628.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/62055
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!