首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[C++11札记]: std::bind

[C++11札记]: std::bind

作者头像
云水木石
发布2019-07-02 11:51:01
发布2019-07-02 11:51:01
1.7K00
代码可运行
举报
运行总次数:0
代码可运行

在上一篇文章中,我们提到可调用对象(callable object),其中一种就是std::bind表达式。在这篇文章中,我们来谈谈std::bind表达式。

关于std::bind的定义如下:

代码语言:javascript
代码运行次数:0
运行
复制
template< class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );template< class R, class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );

关于其解释可以参看:http://en.cppreference.com/w/cpp/utility/functional/bind

看上去不好理解,咱们还是以一个简单的例子来进行说明,毕竟一个例子胜过千言万语。比如有如下函数实现两个整数相加:

代码语言:javascript
代码运行次数:0
运行
复制
int add(int x, int y) {
   return x + y;    
}

假如现在我们要实现某个整数加上6的函数功能,除了写一个类似的函数:

代码语言:javascript
代码运行次数:0
运行
复制
int add1(int x) {
       return x + 6;    
}

之外,我们还可以复用上面的add函数:

代码语言:javascript
代码运行次数:0
运行
复制
auto add1 = bind(add, placeholders::_1, 6);
cout << add1(2) << endl; // print 8

简单说,bind就是一个函数包装器(function wrapper),在一个通用化函数的基础上,固定一个或多个输入参数,包装成一个更加简化的函数。其好处有:

  1. 代码复用。上面的例子过于简单,可能没有表现出这个好处。但我们可以想象一下加入上面的add函数实现了很复杂的逻辑,通过copy代码的方式实现类似功能,极其容易引入bug。
  2. 易于维护,这其实也是代码复用带来的好处,代码逻辑写在一处比分散在多处更容易维护。

如果说这两点好处还不足以说服我们使用std::bind,那接下来我们要探讨的用法才是std::bind的最大用途。

上一篇文章中,我们曾提过对象的成员函数无法与函数指针相容,主要原因在于类的成员函数都包含有一个隐含的this参数。比如:

代码语言:javascript
代码运行次数:0
运行
复制
class Simple
{
   private:
       int m_id;   public:
       Simple(int id)
       {
           setID(id);
       }       void setID(int id) { m_id = id; }
       int getID() { return m_id; }
};

其中的setID成员函数经过编译器的处理,等价于:

代码语言:javascript
代码运行次数:0
运行
复制
void setID(Simple* const this, int id) { this->m_id = id; }

调用代码

代码语言:javascript
代码运行次数:0
运行
复制
simple.setID(2);

经过编译器处理,成为:

代码语言:javascript
代码运行次数:0
运行
复制
setID(&simple, 2);

这一切都是编译器在处理,对于实现者和调用者并不需要关心这些细节。回想之前的std::bind,我们是否可以将指针绑定到成员函数而包装成另一个函数呢?

代码语言:javascript
代码运行次数:0
运行
复制
#include <functional>
#include <iostream>struct Foo {
   int value;
   void f() { std::cout << "f(" << this->value << ")\n"; }
   void g() { std::cout << "g(" << this->value << ")\n"; }
};void apply(std::function<void()> func) {
   func();
}int main() {
   Foo foo1{1};
   Foo foo2{2};   apply(std::bind(&Foo::f, &foo1));
   apply(std::bind(&Foo::g, &foo2));
}

在上述代码中,我们将Foo的成员函数包装成了std::function这样的类型,从而可以用在回调等场景。

当然,在实际项目的代码中,还有很多bind的用途,比如chromium项目中就有大量的bind和callback,虽然里面并不是使用的std::bind,而是使用自己定义的base::bind,但在原理上是差不多的

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云水木石 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档