仿函数是STL六大部件部件中最简单的。所谓仿函数就是一个类里面重载小括号,用这个类创造的对象就是仿函数对象。仿函数只为算法服务,给算法以独特的准则。
文章目录
1 仿函数简介
1.1 特征
仿函数必须重载圆括号。
1.2 分类
1、算术类:进行加减运算的;
2、逻辑运算类:对比特位进行操作的;
3、相对关系类:比大小。
1.3 示例
单纯仿函数的示例如下:
融入了算法的仿函数示例如下(以sort为例):
其中第1个是默认的排序算法类型,第2个使用了一个函数作为排序类型,第3个用了定义出的一个行为像函数的类(自己定义的仿函数)的对象来作为排序类型,而前三个并不是仿函数。第4个和第5个使用了仿函数类型,且后面加上了小括号,即传入的应该是临时对象。
2 仿函数适配器
2.1 STL仿函数继承的父类
自己定义的仿函数是没有继承关系的,是没有融入STL的;而标准库的仿函数都继承了特定的几个类。
unary_function表示有一个操作数,如一个数的取反操作。
binary_function表示有两个操作数,如两个数的比大小操作。
这种STL的仿函数接受模板操作,所继承的类没有数据,也没有函数。
仿函数的可适配条件就是要让各部分合适的继承父类。如适配器要问问题,如binary_function第二参数是什么,就需要仿函数来回答,要回答问题就必须必须继承某一个。因此如同算法问问题迭代器回答一样,STL的仿函数也要回答适配器的问题。
所以自己想创造仿函数,要选择适当的某一个父类来继承。
2.2 三个重要的typedef
仿函数想要被适配,需要回答问题,方法是继承一个父类,父类回答问题的方式是typedef。
如上图,在上面2中提出了关于进行回答问题的typedef:
关于less< int >的定义:
仿函数的对象,必须能够回答三个问题,才能与适配器进行搭配:
1、Operation::first_arguement_type:第一参数类型是否合理(能否转换成int)
2、Operation::second_arguement_type:第二参数类型是否合理(能否转换成int)
3、Operation::result_type:返回类型是否合理(能否转换成bool)
例子见下面3.1。
3 仿函数适配器示例
在STL第一讲的示例中就出现了两个仿函数适配器,下面对这两个适配器进行讲解。
3.1 binder2nd
绑定第二参数,将第二参数绑定为40,仿函数less是比小,用小括号得到一个临时对象,故使用binder2nd绑定40,即作用是比40小。
对外界的接口是bind2nd,提供类名Operation,也就是仿函数,把这个仿函数的类型传给内部函数,内部调用函数为binder2nd。这里绿色的op是一个操作,带上了小括号代表是仿函数less< int >的临时对象,绿色的value将记录另一个对象40。最后返回的是调用op把一个值根据第二参数变成了两个值比较,即less函数,并且将less比大小的数据定为与40比较。
关于上文的typedef:如Operation::second_arguement_type,这里要问第二参数,回答为value,即40,若40可以转化为Operation的类型int,则能够回答,否则会出现error!running time error!同理,x必须是Operation::first_arguement_type类型的东西,这里less< int >能够回答。例子中返回类型需要是pred,故op操作得到的对象也必须是个bool类型。
3.2 not1
继续修饰上面的binder2nd后的东西。本来是为了得到“小于40”,但加了not1,得到的就是“大于40”了。故not1功能是取反。
如上例,过程同binder2nd,下面来宏观看一下:首先进行函数模板的实参推导,即Predicate的类型被推导;然后返回一个临时对象unary_negate< Predicate >(pred),故调用其构造函数,传入函数中,将x记在pred中,通过对小括号的操作符重载进行取反操作。具体顺序请参考图上箭头。
3.3 bind(新)
使用新的名字(下图左列)来取代旧的(下图右列):
可以绑定任意数量的实参,具体功能如下例: