最近一个月读了读《STL源码剖析》,有点散乱,打算把一些比较重要的东西记录下来。
空间适配器那部分有点读的不是很明白,也不是很仔细,主要是我个人对于这些空间上的管理不是很感兴趣 ¿,因此只是略略的读了一遍。
而迭代器这部分就比较有意思了,因此我决定从迭代器这部分开始比较仔细的做笔记。
本文章主要讲一讲 Traits 编程技法。
在这之前需要了解一下C++的一些复杂特性,以下主要说模板特化与偏特化。
模板
如下是一个基本的模板类写法,使用了仿函数(重载了括号运算符的类。简而言之,可以把一个类对象当做一个函数似的去调用)
| 12
 3
 4
 5
 6
 7
 
 | template <class T>class Equal() {
 bool operator() (T& x, T& y) {
 return x == y;
 }
 }
 
 
 | 
但是这个模板真的能够通用吗,答案是否定的,比如浮点数之间的比较,众所周知浮点数的存储是有误差的,因此两个浮点数的大小比较不能简单的用 == 的方式,而应该定义为相差的绝对值不超过eps(eps需要多少由你自己的需求决定)。
但是我们这个模板在大部分情况下是通用的,只是在少数情况下需要替换,怎么办?
特化
此时模板特化就派上用场了,注意写法,此处已经全部特化就不用谢模板参数 T 了。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | const double eps = 1e-12;
 template <class T>
 class Equal {
 public:
 bool operator()(T& x, T& y) {
 cout << "Equal" << endl;
 return x == y;
 }
 };
 
 template <>
 class Equal<double> {
 public:
 bool operator() (double& x, double& y) {
 cout << "Equal<double>" << endl;
 return fabs(x - y) <= eps;
 }
 };
 
 
 | 
当对模板进行实例化时,编译器先去找有没有特化版本,有的话就使用特化版本,否则就使用普通的模板。
这样,我们就能够对一些特殊情况使用模板了。
偏特化
偏特化是对模板本身进行了一些特殊限制,与特化有所区别,其本身仍然是一个模板,具体见代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | template <class T>  class func {
 public:
 void operator()() {
 cout << "func" << endl;
 }
 };
 
 template <class T>
 class func<T*> {
 public:
 void operator()() {
 cout << "func<T*>" << endl;
 }
 };
 
 template <class T>
 class func<const T*> {
 public:
 void operator()() {
 cout << "func<const T*>" << endl;
 }
 };
 
 
 | 
偏特化本身还是模板,只不过对模板参数的类型进行了一定的限制,上述两种偏特化对原生指针和 const 指针进行了偏特化,这样,若模板参数为指针类型,我们就能对其进行一定程度的 “定制”。
偏特化是不是只有类似于以上两种写法呢,当然不是,如下也是可以的。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | template <class _Tp1, class _Tp2>class test {
 public:
 void operator()() { cout << "test" << endl; }
 };
 
 template <class _Tp1>
 class test<_Tp1, int*> {
 public:
 void operator()() { cout << "test<_Tp1, int*>" << endl; }
 };
 
 template <class _Tp1, class _Tp2>
 class test<_Tp1, _Tp2*> {
 public:
 void operator()() { cout << "test<_Tp1, _Tp2*>" << endl; }
 };
 
 
 | 
测试代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 
 | 
 
 
 
 
 
 
 
 
 #include <bits/stdc++.h>
 
 using namespace std;
 
 const double eps = 1e-12;
 
 
 
 
 
 
 
 template <class T>
 class Equal {
 public:
 bool operator()(const T& x, const T& y) const {
 cout << "Equal" << endl;
 return x == y;
 }
 };
 
 template <>
 class Equal<double> {
 public:
 bool operator()(const double& x, const double& y) const {
 cout << "Equal<double>" << endl;
 return fabs(x - y) <= eps;
 }
 };
 
 
 
 
 
 
 
 template <class T>
 class func {
 public:
 void operator()() { cout << "func" << endl; }
 };
 
 template <class T>
 class func<T*> {
 public:
 void operator()() { cout << "func<T*>" << endl; }
 };
 
 template <class T>
 class func<const T*> {
 public:
 void operator()() { cout << "func<const T*>" << endl; }
 };
 
 
 
 
 
 
 
 template <class _Tp1, class _Tp2>
 class test {
 public:
 void operator()() { cout << "test" << endl; }
 };
 
 template <class _Tp1>
 class test<_Tp1, int*> {
 public:
 void operator()() { cout << "test<_Tp1, int*>" << endl; }
 };
 
 template <class _Tp1, class _Tp2>
 class test<_Tp1, _Tp2*> {
 public:
 void operator()() { cout << "test<_Tp1, _Tp2*>" << endl; }
 };
 
 int main() {
 cout << "----------------" << endl;
 Equal<int> e1;
 Equal<double> e2;
 e1(1, 2);
 e2(1, 2);
 cout << "----------------" << endl;
 func<int> f1;
 func<int*> f2;
 func<const int*> f3;
 f1();
 f2();
 f3();
 cout << "----------------" << endl;
 test<int, int> t1;
 test<int, int*> t2;
 test<int, char*> t3;
 t1();
 t2();
 t3();
 cout << "----------------" << endl;
 return 0;
 }
 
 
 | 
Traits编程技法
首先简单