C++11绑定器bind及function机制

本文深入探讨C++中的函数对象、绑定器bind1st、bind2nd以及C++11的bind和function机制。通过示例解释了函数对象的概念,以及为何需要绑定器来转换函数对象以匹配不同接口。C++11的bind提供更通用的绑定功能,而function作为回调功能的实现,能保存上下文并调用不同类型的可调用对象。文章通过源码分析和示例代码帮助理解这两个机制的底层原理。
摘要由CSDN通过智能技术生成

🚀 优质资源分享 🚀

学习路线指引(点击解锁) 知识定位 人群定位
🧡 Python实战微信订餐小程序 🧡 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
💛Python量化交易实战💛 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

前言

之前在学muduo网络库时,看到陈硕以基于对象编程的方式,大量使用boost库中的bindfunction机制,如今,这些概念都已引入至C++11,包含在头文件中。

本篇文章主要梳理C++绑定器相关的内容以及C++11中引入的function机制,其中绑定器主要有三种:bind1stbind2ndbind(C++11)。学完本篇内容,将对C++绑定器及function机制等的底层实现有深刻理解,那么我们开始说吧。

函数对象

首先说说函数对象,之所以说函数对象,是因为绑定器、function都涉及到该部分概念。函数对象实际上是类调用operator()()小括号运算符重载,实现像在“调用函数”一样的效果,因此还有个别名叫“仿函数”。函数对象示例代码如下:

class Print {
public:
    void operator()(string &s) { cout << s << endl; }
};

int main() {
    string s = "hello world!";
    Print print; //定义了一个函数对象print
    print(s);
    return 0;
}

上面代码print(s);语句,看似像函数调用,其实是类对象print调用其小括号运算符重载print.operator(string &s)print就是一个函数对象,至此对函数对象就有了基本的认识。

剖析绑定器bind1st、bind2nd

了解了函数对象,接下来我们说说绑定器,为什么需要绑定器?在使用STL时经常会遇到STL算法中需要传递某元函数对象,比如在写sort时,第三个参数决定了我们的排序规则,用来接收一个“比较器”函数对象,该函数对象是一个二元的匿名函数对象,形如greator()或者less()。二元函数对象的意思是,这个函数对象的小括号运算符重载函数接收两个参数,那么几元就表示接收几个参数。下面是库中自带的greaterless模板类的源码实现,可以看到是对小括号运算符重载的实现,sort第三个参数接收该模板类的二元匿名函数对象。

  template<typename \_Tp>
    struct greater : public binary\_function<\_Tp, \_Tp, bool>
    {
      _GLIBCXX14_CONSTEXPR
      bool
      operator()(const _Tp& __x, const _Tp& __y) const
      { return __x > __y; }
    };

  template<typename \_Tp>
    struct less : public binary\_function<\_Tp, \_Tp, bool>
    {
      _GLIBCXX14_CONSTEXPR
      bool
      operator()(const _Tp& __x, const _Tp& __y) const
      { return __x < __y; }
    };

再回到刚才的问题,那为什么需绑定器?由于STL接口的限制,有时我们拿到的函数对象和特定STL算法中要接收的函数对象在参数上并不匹配,意思就是需要传递一个一元函数对象,你有一个二元函数对象,那可以通过绑定器提前绑定二元函数对象的其中一个参数,使得最终返回的是一个一元函数对象,那么从二元函数对象到一元函数对象的转换过程,就需要绑定器去实现。

如STL中的泛型算法find_if,可用来查找可变长数组vector中符合某个条件的值(这个条件比如是要大于50,要小于30,要等于25等等)。其第三个参数需要传递一个一元函数对象,假如现在要找到第一个小于70的数,可将绑定器与二元函数对象结合,转换为一元函数对象后传递给find_if

我们知道系统自带的greater()less()模板类对象是二元匿名函数对象,所以需要通过绑定器将其转换为一元函数对象,可以通过bind1stbind2nd去绑定,顾名思义,前者对二元函数对象的第一个参数进行绑定,后者对二元函数对象的第二个参数进行绑定,两个绑定器均返回一元函数对象,用法如下:

sort(vec.begin(), vec.end(), greater<int>()); //从大到小对vector进行排序
find\_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70));
find\_if(vec.begin(), vec.end(), bind2nd(less<int>(), 70));

两个绑定器分别提前绑定了一个参数,使得二元函数对象+绑定器转换为一元函数对象:

operator()(const T &val)
greater a > b ====> bind1st(greater<int>(), 70) ====> 70 > b
less    a < b ====> bind2nd(less<int>(),    70) ====> a < 70

下面给出bind1st绑定过程图,二元函数对象绑定了第一个数为70,变为一元函数对象,传递给find_if泛型算法,此时find_if所实现的功能就是:找出有序降序数组中第一个小于70的数,所以find_if返回指向65元素的迭代器:

file:///Users/guochen/Notes/docs/media/16656563650484/16657214749366.jpgimage

以上就是绑定器的概念。因此需要绑定器的原因就很明显了,绑定器可以返回一个转换后的某元函数对象,用于匹配泛型算法。

根据上面的理解,接下来实现一下bind1st,代码实现如下:

/*可以看到 自己实现的绑定器本质上也是个函数对象 调用operator()进行绑定*/
template<typename Compare, typename T>
class 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值