判别式(predicate):
返回为bool类型(或者可以隐式转换成bool类型)的函数。在STL中,判别式有着广泛的用途。标准关联容器的比较函数就是判别式:对于像find_if以及各种与排序有关的算法,判别式往往也被作为参数来传递。
纯函数(pure function):
返回值仅仅以依赖于其参数的函数。例如,假设f是一个纯函数,x和y是两个对象,那么只有当x或者y的值发生变化的时候,f(x, y)的返回值才可能发生变化。
在C++中,纯函数所能访问的数据应该仅限于参数以及常量,如果一个纯函数需要访问那些可能会在两次调用之前发生变化的数据,那么用相同的参数在不同的时刻调用该函数就有可能会得到不同额结果,这将与纯函数的定义像矛盾。
判别式类(predicate class):
是一个函数子类,它的operator()函数是一个判别式,也就是说,它的operator()返回true或者false。STL中凡是能接受判别式的地方,也可以接受一个判别式类对象。
对于用作判别式的函数对象,使用时它会被拷贝存起来,然后再使用这个拷贝。这一特性要求判别式函数必须是纯函数。
以一个反例来阐述判别式不是纯函数的后果:
class BadPredicate // 判别式类(带状态)
{
public:
BadPredicate() : timesCalled(0) { }
bool operator () (const Widget&) { return ++timesCalled == 3; }
private:
int timesCalled;
}
使用BadPredicate删除vector中的第三个Widget:
std::vector<Widget> datas;
...
datas.erase(std::remove_if(datas.begin(), datas.end(), BadPredicate()), datas.end());
这段代码看起来合理,其是它不只会删除datas中容器的第三v个元素,还是删除第六个。
你需要了解remove_if的实现:
template<typename FwdIterator, typename Predicate>
FwdIterator remove_if(FwdIterator begin, FwdIterator end, Predicate p)
{
begin = find_if(begin, end, p);
if (begin == end) return begin;
else
{
FwdIterator next = begin;
return remove_copy_if(++next, end, begin, p);
}
}
调用remove_if,p先被传递给find_if,然后又被传递给remove_copy_if,由于是拷贝传递,每次传入的Prdicate对象中timesCalled都是0,因此位置3和位置6的元素最终都会被删除。
STL中凡是需要判别式的地方,既可以接受一个真正的函数,也可以接受一个判别式的对象。反之依然,STL总凡是可以接受一个真正的函数,也可以接受一个判别式函数。