谓词函数predicates和仿函数functors

来源:互联网 发布:外星文明不存在 知乎 编辑:程序博客网 时间:2024/05/20 04:14

谓词函数是一个判断式,一个返回bool值的函数或者仿函数。

C++ standard library P264:并非所有返回布尔值的仿函数都是合法的谓词函数。使用两个相同的参数调用一个一元谓词函数,应该总是返回相同的结果(与调用次数无关)。

使用以下代码移除一组元素中的第三个元素,却发生了意想不到的事情。

#include <iostream>#include <list>#include <algorithm>using namespace std;template <class T>void print_elements(const T& container){for(typename T::const_iterator it = container.begin(); it != container.end(); ++it){cout << *(it) << " ";}cout << endl;}class Nth{private:int nth, count;public:Nth(int n): nth(n), count(0) {}int operator() (int){return nth == ++count;}};int main(){list<int> coll;for (int i = 0; i < 9; ++i)coll.push_back(i);    print_elements(coll);list<int>::iterator pos;pos = remove_if(coll.begin(), coll.end(), Nth(3));coll.erase(pos, coll.end());print_elements(coll);return 0;}

运行结果为:

coll: 1 2 3 4 5 6 7 8 9

nth removed: 1 2 4 5 7 8 9

为什么会产生这样的结果呢?这是因为remove_if内部实现中,首先调用了find_if函数来查找第一个满足pred的迭代器位置。然后再处理剩余的元素,代码如下:

template<class ForwardIterator, class Predicate>ForwardIterator std::remove_if(ForwardIterator beg, ForwardIterator end, Predicate op){beg = find_if(beg, end, op);if(beg == end){return beg;}else{ForwardIterator next = beg;return remove_copy_if(++next, end, beg, op);}}

可以看到,对后续元素调用remove_copy_if,将谓词函数返回false的元素copy至beg处,而谓词函数是以传值方式传递的,所以在remove_copy_if中,第三个元素也会被remove。

所以,一个合法的谓词函数,它的行为不应该取决于被调用次数,谓词函数不应该因为被调用而改变自身状态。故一般情况下应该将operator()声明为const成员函数。

敲代码的时候犯了一个小错误,写仿函数的operator()时,由于操作符中并未使用额外的参数,所以函数定义时默认成了不传参,结果编译错误。

for(; __first != __last; ++__first)        if(!bool(__pred(*__first)))          {            *__result = _GLIBCXX_MOVE(*__first);            ++__result;          }

可以看到​​,​在remove_if算法中,使用谓词函数时传入了*(__first),所以谓词函数定义时,形参应与容器元素类型相同,更不能省略。

0 0
原创粉丝点击