最近一个月读了读《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
/**
* -*- coding: utf-8 -*-
* @file test.cpp
* @date 2020/12/30 16:05:58
* @author zzpw
* @version 1.0
* @license: (C)Copyright 2020-2020
* @description: None
*
*/
#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编程技法

首先简单