13.1.2  仿函数的作用

13.1.2 仿函数的作用

程序员通常以下面4种形式使用仿函数:

1)作为排序规则。

2)拥有内部状态。

3)算法for_each()的返回值。

4)作为判断式。

1.仿函数作为排序规则

仿函数可以将已序的数据放入容器中。使用通常的运算符“operator<”有时不能对这些元素排序,因此需要自定义特别的规则来实现排序的目的,而仿函数可以作为排序规则,详见例13-1。

例13-1

978-7-111-51399-5-Chapter13-3.jpg

978-7-111-51399-5-Chapter13-4.jpg

例13-1的执行结果为:

978-7-111-51399-5-Chapter13-5.jpg

例13-1使用了仿函数类person_sort_rule。该类定义了operator()函数。该函数对输入的数据的lastname字段进行比较。所有元素以此作为排序规则进行排序。若以一般的函数作为排序规则,则比较困难。由于set具有自动排序性,这是不能避免的,但程序员可以设计自己的排序规则。

2.仿函数可以拥有内部状态

仿函数还可以使程序在同一时刻拥有多个状态。函数传递数值的方式也有两种:通过值传递;通过引用传递。仿函数是采用第一种方式:值传递。算法并不会改变随参数而来的仿函数的状态。仿函数参数采用“传递值”方式的好处是可以传递常量或临时表达式;缺陷是无法改变仿函数的状态。算法可以改变仿函数的状态,但无法存取或改变其最终状态,改变的仅仅是仿函数的副本。有时需要存取最终状态,其关键是怎样从算法中获取结果。

从使用仿函数的算法中获取结果或反馈的方法通常有两种:

1)以引用的方式传递仿函数。若希望能够以引用的方式传递仿函数,则需要在调用算法时明确表示仿函数型别是引用型别。

2)使用for_each()算法的返回值。

下面以例13-2来说明上述知识点。

例13-2

978-7-111-51399-5-Chapter13-6.jpg

978-7-111-51399-5-Chapter13-7.jpg

例13-2的执行结果为:

978-7-111-51399-5-Chapter13-8.jpg

本例是以仿函数产生一个整数序列。当仿函数的运算符operator()被调用时,函数会返回整数值并累加1。可通过构造函数的参数指定初始值。例13-2还使用了generate()和gen-erate_n()算法。这两个算法的作用是:产生数值用以写入群集内。在使用仿函数sequence()时,均使用了初始参数,该初始参数可作为产生序列的初始值。算法generator_n()会连续n次改写元素值,产生n个元素。例如,

978-7-111-51399-5-Chapter13-9.jpg

上述语句会产生以42为起始值的整数序列。

通过修改operator()可以产生更加复杂的序列。例如,

978-7-111-51399-5-Chapter13-10.jpg

上述程序的执行结果为:

978-7-111-51399-5-Chapter13-11.jpg

若要实现以引用的方式传递函数,读者可将例13-2修改为例13-3。

例13-3

978-7-111-51399-5-Chapter13-12.jpg

例13-3的执行结果为:

978-7-111-51399-5-Chapter13-13.jpg

3.算法for_each()的返回值

若使用算法for_each(),则不必实例化仿函数的“引用计数版本”来存取最终状态。算法for_each()有其独门绝技,这是其他算法所没有的,即可以返回其仿函数。通过算法for_each()的返回值可以获取仿函数的状态,详见例13-4。

例13-4

978-7-111-51399-5-Chapter13-14.jpg

978-7-111-51399-5-Chapter13-15.jpg

例13-4的执行结果为:

978-7-111-51399-5-Chapter13-16.jpg

在语句for_each(col.begin(),col.end(),MeanV())中,MeanV()产生一个反函数用于记录元素数量,并计算所有元素的总和。此仿函数传递给算法for_each(),后者会针对容器内每个元素调用仿函数。而返回的仿函数被赋值给mv。调用仿函数的成员函数value(),即可获取相应的平均值了。

4.判断式可返回仿函数的状态

所谓判断式,即返回布尔值的一个函数或仿函数。对于STL来说,并不是所有返回布尔值的函数是合法的判断式(谓词)。这样会导致很多意想不到的结果。

例13-5

978-7-111-51399-5-Chapter13-17.jpg

978-7-111-51399-5-Chapter13-18.jpg

例13-5的执行结果为:

978-7-111-51399-5-Chapter13-19.jpg

例13-5中使用了一个仿Nth()函数,当被重复调用时,此仿函数会返回true。若将其传递给算法remove_if()时,此算法会将所有符合条件的元素删除。