最近一个月读了读《STL源码剖析》,有点散乱,打算把一些比较重要的东西记录下来。
空间适配器那部分有点读的不是很明白,也不是很仔细,主要是我个人对于这些空间上的管理不是很感兴趣 ¿,因此只是略略的读了一遍。
而迭代器这部分就比较有意思了,因此我决定从迭代器这部分开始比较仔细的做笔记。
本文章主要讲一讲 Traits 编程技法。
在这之前需要了解一下C++的一些复杂特性,以下主要说模板特化与偏特化。
模板
如下是一个基本的模板类写法,使用了仿函数(重载了括号运算符的类。简而言之,可以把一个类对象当做一个函数似的去调用)
1 2 3 4 5 6 7
| template <class T> class Equal() { bool operator() (T& x, T& y) { return x == y; } }
|
但是这个模板真的能够通用吗,答案是否定的,比如浮点数之间的比较,众所周知浮点数的存储是有误差的,因此两个浮点数的大小比较不能简单的用 == 的方式,而应该定义为相差的绝对值不超过eps(eps需要多少由你自己的需求决定)。
但是我们这个模板在大部分情况下是通用的,只是在少数情况下需要替换,怎么办?
特化
此时模板特化就派上用场了,注意写法,此处已经全部特化就不用谢模板参数 T 了。
1 2 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; } };
|
当对模板进行实例化时,编译器先去找有没有特化版本,有的话就使用特化版本,否则就使用普通的模板。
这样,我们就能够对一些特殊情况使用模板了。
偏特化
偏特化是对模板本身进行了一些特殊限制,与特化有所区别,其本身仍然是一个模板,具体见代码
1 2 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 指针进行了偏特化,这样,若模板参数为指针类型,我们就能对其进行一定程度的 “定制”。
偏特化是不是只有类似于以上两种写法呢,当然不是,如下也是可以的。
1 2 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; } };
|
测试代码
1 2 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编程技法
首先简单