[6 函数子类及函数] 40. 若一个类是函数子类,则应使它可配接

假设有一个包含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:

https://www.cnblogs.com/iyoyos/p/4157669.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值