使用STL仿函数和判断式来降低复杂性并改善可读性

ZDNet软件频道 时间:2003-10-30 作者:周靖 |  我要评论()
本文关键词:cpptips
标准模板库(STL)包含C++程序员不可或缺的许多东西,STL的概念包括容器,范围,算法,仿函数.本文着重讲解仿函数,它本质上是一个类,这个概念在STL之前便已存在,STL只是从另一个角度来看待它。继续阅读本文,你就能体会到个中三味。
本文译自Builder.com,未经许可请勿转载

标准模板库(STL)包含C++程序员不可或缺的许多东西。它还有力证明了C++的概念化编程能力。STL的概念包括容器(container)、范围(range)、算法(algorithm)以及仿函数(functor)。本文着重讲解仿函数,它本质上是一个类,但通过重载operator(),所以行为与函数相似。这个概念在STL之前便已存在,STL只是从另一个角度来看待它。继续阅读本文,你就能体会到个中三味。

 

算法、范围和函数

STL以泛型方式来处理函数。假如一个参数的行为应该与函数相仿,STL算法就不关心它是一个实际的C++函数,还是一个仿函数。出于本文的目的,假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)。

STL算法适用于范围。你可使用函数,并将它们应用于一个范围中的每个元素(参见清单A)。这样一来,就可以处理三种类型的函数:

  • 获取零个参数的函数,也称为“生成器”(generators),它们能生成范围。例如,假定一个函数能生成斐波那契数字,那么对该函数的每一个调用都能生成斐波那契数列中的下一个数字。
  • 获取一个参数的函数(一元函数)。
  • 获取两个参数的函数(二元函数)。

这其实已覆盖了大多数情况。极少数情况下,你要求函数获取3个或者3个以上的参数。在这种情况下,可考虑采取其他方式。例如,可将多个参数打包到一个结构中,再按引用传递它。

仿函数:用途和适用的场合

之所以要开发仿函数(functors),是因为函数不能容纳任何有意义的状态。例如,使用函数,你不能为某个元素加一个任意值,再将其应用于一个范围。但是,使用仿函数可轻易做到这一点,如清单B所示。

这演示了仿函数的一个主要优点——它们可以有背景(context)或状态。下面是使用仿函数时要记住的要点:

  • 仿函数以传值方式传给一个算法。
  • 每次只能应用一个仿函数,方法是为范围中的每个元素应用operator()。
  • 使用仿函数,可对范围中的每个函数做某事(比如为每个元素都乘以5),可基于整个范围来计算某个有意义的结果(比如求所有元素的平均值),或者同时进行这两种操作。
  • 对于一个给定的范围,仿函数不知道它要应用于多少个元素。

假定你要创建一个函数,要求它在给定一个范围的情况下,能为每个元素都返回当前已处理的所有元素的平均值。换言之:

  • 处理x1时,返回x1
  • 处理x2时,返回(x1 + x2) / 2
  • 处理x3时,返回(x1 + x2 + x3) / 3

清单C展示了怎样实现这个任务。

 

只要亲自编写和使用一下仿函数,就会体会到它具体如何降低复杂性。你不必关心整个范围,只需将注意力集中在一个元素上。这同时还有助于改善代码的可读性。清单D给出了示范性的generate_fibonacci代码。

 

 

前面讲述的都是一元仿函数。二元仿函数同等重要。二元仿函数同时应用于两个范围,或者应用于某个范围中的两个元素。二元仿函数的operator()要求获取两个参数,而不是一个。假定你有两个范围,分别有相同数量的元素,而你希望构建一个新的范围,比如:

  • 第一个元素:x1 * y1
  • 第二个元素:- x2 * y2
  • 第三个元素:x3 * y3
  • 第四个元素:- x4 * y4,等等。

清单E给出了一个示范性的实现。


百度大联盟认证黄金会员Copyright© 1997- CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号 京ICP备09041801号-159
京公网安备:1101082134