STL_Function
¶1 仿函数的概念
仿函数(functors)是早期的命名,C++标准规格定案后采用的名称是函数对象(function objects)。就现实意义而言,“函数对象”比较贴切,一种具有函数特质的对象。不过,就其行为而言,以及就中文用词的清晰漂亮与独特性而言,“仿函数”依次比较突出。
《STL源码剖析》 – P413
仿函数其实就是一个“行为类似函数”的对象,为了能够“行为类似函数”,其类别定义中必须自定义(或说改写、重载)function call 运算子(operator()
),拥有这样的运算子后,我们就可以在仿函数的对象后面加上一堆小括号,以此调用仿函数所定义的 operator()
,如下:
1 |
|
输出结果如下所示:
注意:
- 代码中
boolalpha
的作用:让输出流将 bool 解析成为 true 或者 false,当使用boolalpha
后,以后的 bool 类型结果都将以 true 或 false 形式输出,除非使用noboolalpha
取消boolalpha
流的格式标志。头文件<iostream>
- 在STL中,当需要传递仿函数对象的时候,通过采用最后一种方法,因为传递进去仅仅为了给容器内部成员赋值,所以没必要生成对象,产生临时对象即可。
- STL 仿函数与 STL 算法之间的关系如图所示:
《STL源码剖析》 – P414
仿函数扮演一种“策略”角色,可以让 STL 算法有更灵活的演出,而更加灵活的关键,在于 STL 仿函数的可配接性 (adaptability)。STL 仿函数应该有能力被函数配接器(function adapter
)修饰,彼此像积木一样地串接,为了拥有配接能力,每个仿函数必须定义自己的相应型别,就像迭代器如果要融入整个 STL 大家庭,也必须依照规定定义自己的 5 个相应型别一样,这些相应型别是为了让配接器能够取出,获得 仿函数的某些信息。相应型别都只是一些 typedef,所有必要操作在编译期就全部完成了,对程序的执行效率没有任何影响,不带来额外负担。
仿函数的相应型别主要用来表现函数的参数型别和返回值,为了方便起见,<stl_function.h>
定义了两个 classes,分别代表一元仿函数和二元仿函数,其中没有任何数据成员和成员函数,唯有一些型别定义,任何仿函数,只要依个人需求选择继承其中一个 class,便自动拥有了那些相应型别,也就自动拥有了配接能力。
1 | // ~ 一元运算符 |
《STL源码剖析》 – P415 - P416
¶2. 仿函数的分类
¶2.1 算术类仿函数
STL 内建的“算术类仿函数”,支持加法、减法、乘法、除法、取余和否定运算,除了否定运算是一元运算,其他都是二元运算。
1 | template <class T> |
测试程序如下:
1 |
|
测试结果如下:
《STL源码剖析》 – P418 - P419
证同元素(identity element)
所谓“运算 op 的证同元素”,意思是数值 A 若与该元素做 op 运算,会得到 A 自己,加法的证同元素为 0,因为任何元素加上 0 仍然是自己;乘法的证同元素是 1,因为任何元素乘以 1,因为任何元素乘以 1仍然是自己。
1 | // 证同元素(并非标准STL所要求) |
《STL源码剖析》 – P420
¶2.2 关系运算类仿函数
STL 内建的“关系运算类仿函数”,支持等于、不等于、大于、大于等于、小于和小于等于六种运算,每一个都是二元运算。
1 | template <class T> |
测试程序如下:
1 |
|
测试结果如下:
例子使用三种方式配合排序算法实现排序:
- 使用默认的 comp :
operator <
- 使用用户自定义的 comp :
myfunction
- 使用仿函数 :
less<int>()
《STL源码剖析》 – P420 - P422
STL之仿函数实现详解,<-- 例子来源
¶2.3 逻辑运算类仿函数
STL 内建的“ 逻辑运算类仿函数”,支持与或非三种运算,与或为二元运算,非为一元运算。
1 | template <class T> |
测试程序如下:
1 |
|
测试结果如下:
《STL源码剖析》 – P422 - P423 <-- 例子来源
¶2.4 证同、选择、投射
这一节介绍的仿函数,都只是将其参数原封不动地传回,其中某些仿函数对传回的参数有可以的选择,或是刻意忽略,之所以不在 STL 或其他泛型程序设计过程中直接使用原本极其简单的 identity、project、select 等操作,而在要划分一层出来,全是为了间接性 – 间接性是抽象化的重要工具。
1 | // @ 证同仿函数,主要用于 RB tree 或者 hashmap 里面 key = value 情况 |
《STL源码剖析》 – P423 - P424
函数配接器内容见 STL_Adapter
¶3. 参考资料
《STL源码剖析》
MiniSTL / Function 部分