C++如何写adaptable仿函数

关于仿函数很多博客上都有,形式很简单,用途也很多。
一句话总结:重载了()运算符的类可以称之为仿函数functor
现在写一个“比较”

class MyLess{
public:
    bool operator()(int a, int b){
        return a < b;
    }
}; 

大多数人会这样写,其实这样写没有错,而且基本所有算法都可以通过
比如:

class MyLess{
public:
    bool operator()(int a, int b){
        return a < b;
    }
};
class Less10{
public:
    bool operator()(int a){
        return a < 10 ? true : false;
    }   
};
int main() {
    vector<int> v{1, 40, 5, 60, 5, 6};
    cout<<count_if(v.begin(), v.end(), Less10())<<endl;
    sort(v.begin(), v.end(), MyLess());
    for(auto i : v)
        cout<<i<<" ";
    cout<<endl;
}

上面两个仿函数MyLess、Less10。两个算法count_if、sort。
这样的仿函数基本上可以用stl中所有的算法。
看看STL中less怎么写的吧

template <class T>
struct less : public binary_function<T, T, bool> {
    bool operator()(const T& x, const T& y) const { return x < y; }
};

除了模板,还有就是less继承了个binary_function,这个是什么鬼?
为什么要继承它?继承它有啥用?
看一个例子:

class MyLess{
public:
    bool operator()(int a, int b){
        return a < b;
    }
};
int main() {
    vector<int> v{1, 40, 5, 60, 5, 6};
    cout<<count_if(v.begin(), v.end(), bind2nd(less<int>(), 50))<<endl;
}

bind2nd这个叫绑定器,可以绑定一个仿函数的第二个参数。
为啥要使用绑定器?看看第段代码,有没有发现我统计数组中小于10的元素个数太单一了?一点都没有可扩展性,当我们要小于50的时候又得再写一个仿函数,太累了。所以绑定器产生了,现在C++11的绑定都是用bind这个函数(这个函数太厉害了,比bind1nd,bind2nd强大的多,有机会可以去了解下)
回到正题,如果我们把less()换成我们自己写的仿函数,编译就有问题,为啥呢?抛开模板,就是没有继承那个什么鬼了。
看看那个鬼张啥样吧

template <class Arg1, class Arg2, class Result>
struct binary_function {
    typedef Arg1 first_argument_type;
    typedef Arg2 second_argument_type;
    typedef Result result_type;
};      

啥?一个成员都木有啊。
其实看STL最大的收获是懂得了typedef的使用,别看简单的一个typedef,几乎在stl中无处不在,绑定器,适配器,萃取器等等,都和typedef密不可分,但是我们正真写程序用typedef的又有几个。
回到正题,我们在看看bind2nd

template <class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) {
  typedef typename Operation::second_argument_type arg2_type;
  return binder2nd<Operation>(op, arg2_type(x));
}

原来bind2nd要用typedef得到第二参数的类型啊,有啥用?为了检查第二参数是否类型正确,如果转换不了那就直接出错
so,结果就出来了,为啥要继承那个鬼。
再继续看看binder2nd吧

template <class Operation> 
class binder2nd
  : public unary_function<typename Operation::first_argument_type,
              typename Operation::result_type> {
protected:
    Operation op;
    typename Operation::second_argument_type value;
public:
    binder2nd(const Operation& x,
              const typename Operation::second_argument_type& y) 
    : op(x), value(y) {}
    result_type operator()(const argument_type& x) const {
    return op(x, value); 
    }
};

这里也需要知道参数类型和返回类型,而且binder2nd本身也是一个仿函数,而且继承了unary_function类

template <class Arg, class Result>
struct unary_function {
    typedef Arg argument_type;
    typedef Result result_type;
};

到此为止我们可以总结了

仿函数如果要融入STL那么需要继承一个类
一个参数用unary_function
两个参数用binary_function

注意:为啥binary_function有两个参数还是继承unary_function呢?
因为binary_function需要别人推导的只有第一参数而已,第二参数类型已经确定,在本类中已经typedef了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值