00 写在前面
仿函数(functors)和适配器(adapter)就到了整个STL的最后部分。虽然这两部分内容不是很多,可以放在一起说。
但作为STL六大部件中的两大部件,这两者还是有很多设计的精华在里面,值得我们学习。
这也是【STL源码剖析】总结笔记的最后一篇。
01 仿函数(Functors)
仿函数的由来
仿函数,顾名思义,就是类似函数的一种东西。在讨论仿函数之前,我们来看看它是如何产生的。
在前面我们见识了很多算法,算法大都提供一个默认版本,但如果用户想根据不同的应用场景对算法进行变换,也是可以的。比如sort排序算法默认是升序的,我们还可以根据操作的不同变为降序等等。
而这里的”操作“就是改变算法的关键。
首先第一种方法是把这个操作写成一个函数,然后在算法的参数中传入函数指针。这样是完全可以实现对算法的改变的,但是会有一个问题,就是不够灵活,不能随意改变。
举个例子,求数组中大于10的数的个数。
int RecallFunc(int *start, int *end, bool (*pf)(int)) {
int count=0;
for(int *i=start;i!=end+1;i++) {
count = pf(*i) ? count+1 : count;
}
return count;
}
bool IsGreaterThanTen(int num) {
return num>10 ? true : false;
}
int main() {
int a[5] = {10,100,11,5,19};
int result = RecallFunc(a,a+4,IsGreaterThanTen);
return 0;
}
我们可以把大于10写为一个函数,再传入原本的算法中。
但如果我们想实现大于任何数,让IsGreaterThanTen(int num)变为IsGreaterThan(int num1,int num2)传入两个参数,那就不可以实现了。(当然定义为全局变量也可以实现)
这时候仿函数就派上用场了。
再举个例子,比如常见的比较大小用的less
template <class T>
struct less:public binary_function<T,T,bool>{
bool operator()(const T&x,const T&y)const{turn x<y};
};
这样定义之后就可以产生一个仿函数对象了。
可以产生仿函数实体,然后调用实体:
less<int> less_obj;
less_obj(3,5);
或者使用临时对象**(常用)**
less<int>()(3,5);
当然,配合算法才是仿函数的目的,只为算法服务。
sort(vi.begin(),vi.end(),less<int>());
### 仿函数与算法
大家可能也注意到了,仿函数需要重载小括号。
而这样的重载可以使其很好地融合于算法之中。
比如算法accumulate,在第二个版本中注意第三个参数
template <class InputIterator,class T,class BinaryOperation>
T accumulate(InputIterator first,InputIterator last,T init,BinaryOperation binary_op){
for(;first!=last