16.3 通用搜索算法f?ind_if()
其实我们并没有那么经常地需要查找一个特定值。我们通常更感兴趣的是在序列中查找符合某种标准的值。如果能够允许我们自己定义查找标准,这样的f?ind操作就更为有用。例如,我们也许希望查找大于42的值,也许希望在不考虑大小写的情况下比较字符串,也许希望找到第一个奇数值,也许希望查找一个地址域值为“17 Cherry Tree Lane”的记录。
根据用户提供的标准进行查找的标准算法是f?ind_if():
显然(当你比较源码时),f?ind_if()的实现与f?ind()的实现很相似,除了前者使用!pred(*f?irst)而非*f?irst != val;即,一旦断言pred()成立,f?ind_if()就立即停止搜索,而不是当一个元素等于给定值时停止。
断言是一种返回true或false的函数。显然,f?ind_if()要求断言接受一个参数,这样就可以说pred(*f?irst)。我们可以容易地编写一个断言来检查值的某种属性,例如“字符串是否包含字母x?”“值是否大于42?”“数是否是奇数?”例如,我们可以通过如下方式在int的向量中查找第一个奇数:
在这个f?ind_if()调用中,f?ind_if()会对每一元素调用odd()直至它找到了第一个奇数。注意,当你将一个函数作为参数传递时,你不应在它的名字后面加上(),因为这样做会调用它。
类似地,我们可以查找一个链表中第一个大于42的元素:
最后这个例子并不是十分令人满意。如果我们下次想找出大于41的元素该怎么办呢?我们不得不编写一个新的函数。那查找大于19的元素又如何?又要编写另一个函数。应该有更好的方法!
如果我们想要与任意的值v进行比较,我们需要某种方法令v成为f?ind_if()的断言的一个隐含参数。我们可以尝试如下(选择v_val作为变量名以避免与其他名称发生冲突):
哟!我们相信编写这段代码的人最终能得到想要的结果,但我们很同情代码的用户和维护者。再次强调:应该还有更好的方法!
试一试
为什么我们讨厌这样使用v呢?请给出这种编程方式可能导致的三种隐晦错误。列出三个应用,你特别讨厌发现这种代码。