假设有一个包含Widget对象指针的list容器:
list<Widget*>::iterator widgetPtrs;
bool isInteresting(const Widget* pw);
现在想找到list中第一个满足isInteresting()的条件的Widget指针:
list<Widget*>::iterator i = find_if(widgetPtrs.begin(), widgetPtrs.end(), isInteresting);
if (i != widgetPtrs.end()) {
// 处理第一个指向有趣Widget的指针
...
}
如果,想找到list中第一个不满足isInteresting()的条件的Widget指针:
list<Widget*>::iterator i = find_if(widgetPtrs.begin(), widgetPtrs.end(), not1(isInteresting));
会编译出错,正确的做法是在not1之前,先将ptr_fun应用在isInteresting上:
list<Widget*>::iterator i = find_if(widgetPtrs.begin(), widgetPtrs.end(), not1(ptr_fun(isInteresting)));
if (i != widgetPtrs.end()) {
// 处理第一个指向有趣Widget的指针
...
}
为什么需要先应用ptr_fun?因为ptr_fun完成了一些类型定义的工作,而isInteresting作为一个函数指针,缺少not1所需要的类型定义。
4个标准的函数配接器(not1,not2,bind1st和bind2nd)都要求一些特殊的类型定义,提供了这些必要的类型定义的函数对象被称为可配接的函数对象;反之,则称为不可配接的。这些特殊的类型定义是:argument_type,first_argument_type,second_argument_type以及result_type。提供这些类型定义最简便的办法是让函数子从特定的基类继承,如果函数子类的operator()只有一个实参,那么它应该从std::unary_function继承;如果函数子类的operator()有两个实参,那么它应该从std::binary_function继承。以下是两个例子:
template<typename T>
class MeetsThreshold: public std::unary_function<Widget, bool> {
private:
const T threshold;
public:
MeetsThreshold(const T& threshold);
bool operator()(const Widget&) const;
...
};
struct WidgetNameCompare: public std::binary_function<Widget, Widget, bool> {
bool operator()(const Widget& lhs, const Widget& rhs) const;
};
注意:传递给unary_function和binary_function的模板参数正式函数子类的operator()的参数类型和返回类型。
一般来说,传递给unary_function或binary_function的非指针类型需要去掉const和引用(&)部分。
struct WidgetNameCompare: public std::binary_function<Widget, Widget, bool> {
bool operator()(const Widget& lhs, const Widget& rhs) const;
};
对于以指针作为参数或返回类型的函数子类,一般的规则是:传给unary_function或binary_function的类型与operator()的参数和返回类型完全相同。
struct PtrWidgetNameCompare: public std::binary_function<const Widget*, const Widget*, bool> {
bool operator()(const Widget* lhs, const Widget* rhs) const;
};
unary_function和binary_function作为函数子类的基类,它们提供了函数对象配接器所需要的类型定义,这样通过简单的继承,我们产生了可配接的函数对象。应用如下:
list<Widget> widgets;
...
// 找到最后一个不符合阈值为10的Widget
list<Widget>::reverse_iterator i1 = find_if(widgets.rbegin(), widgets.rend(), not1(MeetsThreshold<int>(10)));
Widget w(...);
// 找到按WidgetNameCompare定义的规则排序时,在w之前的第一个Widget对象
list<Widget>::iterator i2 = find_if(widgets.begin(), widgets.end(), bind2nd(WidgetNameCompare(), w));
如果我们的函数子类并不是从unary_function或binary_function继承而来的,那么例子则无法编译,因为not1和bind2nd只能用于可配接的函数对象。
bind1st,bind2nd: