读书频道 > 网站 > 网页设计 > 深入应用C++11:代码优化与工程级应用
1.5.3 std::bind绑定器
15-07-07    下载编辑
收藏    我要投稿   
在StackOverflow的最近一次世界性调查中,C++11在所有的编程语言中排名第二, C++11受到程序员的追捧是毫不意外的,因为它就像C++之父Bjarne Stroustrup说的:它看起来就像一门新的语言。C++11新增加了相当多的立即去当当网订购

std::bind用来将可调用对象与其参数一起进行绑定。绑定后的结果可以使用std::function进行保存,并延迟调用到任何我们需要的时候。

通俗来讲,它主要有两大作用:

1)将可调用对象与其参数一起绑定成一个仿函数。

2)将多元(参数个数为n,n>1)可调用对象转成一元或者(n-1)元可调用对象,即只绑定部分参数。

下面来看看它的实际使用,如代码清单1-20所示。

代码清单1-20 std::bind的基本用法

#include <iostream> // std::cout
#include <functional> // std::bind

void call_when_even(int x, const std::function<void(int)>& f)
{
   if (!(x & 1))  // x % 2 == 0
   {
      f(x);
   }
}

void output(int x)
{
   std::cout << x << " ";
}

void output_add_2(int x)
{
   std::cout << x + 2 << " ";
}
int main(void)
{
   {
      auto fr = std::bind(output, std::placeholders::_1);
      for(int i = 0; i < 10; ++i)
      {
         call_when_even(i, fr);
      }
      std::cout << std::endl;
   }
   {
      auto fr = std::bind(output_add_2, std::placeholders::_1);
      for(int i = 0; i < 10; ++i)
      {
         call_when_even(i, fr);
      }
      std::cout << std::endl;
   }
   return 0;
}
输出结果如下:
0 2 4 6 8
2 4 6 8 10

同样还是上面std::function中最后的一个例子,只是在这里,我们使用了std::bind,在函数外部通过绑定不同的函数,控制了最后的执行结果。

我们使用auto fr保存std::bind的返回结果,是因为我们并不关心std::bind真正的返回类型(实际上std::bind的返回类型是一个stl内部定义的仿函数类型),只需要知道它是一个仿函数,可以直接赋值给一个std::function。当然,这里直接使用std::function类型来保存std::bind的返回值也是可以的。

std::placeholders::_1是一个占位符,代表这个位置将在函数调用时,被传入的第一个参数所替代。

因为有了占位符的概念,std::bind的使用非常灵活,如代码清单1-21所示。

代码清单1-21 std::bind的占位符

#include <iostream> // std::cout
#include <functional> // std::bind

void output(int x, int y)
{
   std::cout << x << " " << y << std::endl;
}
int main(void)
{
   std::bind(output, 1, 2)();    // 输出: 1 2
   std::bind(output, std::placeholders::_1, 2)(1); // 输出: 1 2
   std::bind(output, 2, std::placeholders::_1)(1); // 输出: 2 1
   // error: 调用时没有第二个参数
   std::bind(output, 2, std::placeholders::_2)(1);
   std::bind(output, 2, std::placeholders::_2)(1, 2); // 输出: 2 2
   // 调用时的第一个参数被吞掉了
   std::bind(output, std::placeholders::_1,
   std::placeholders::_2)(1, 2);    // 输出: 1 2

   std::bind(output, std::placeholders::_2,
   std::placeholders::_1)(1, 2);    // 输出: 2 1
   return 0;
}

上面对std::bind的返回结果直接施以调用。可以看到,std::bind可以直接绑定函数的所有参数,也可以仅绑定部分参数。

在绑定部分参数的时候,通过使用std::placeholders,来决定空位参数将会属于调用发生时的第几个参数。

下面再来看一个例子,如代码清单1-22所示。

代码清单1-22 std::bind和std::function配合使用

#include <iostream>
#include <functional>

class A
{
public:
   int i_ = 0;

   void output(int x, int y)
   {
      std::cout << x << " " << y << std::endl;
   }
};

int main(void)
{
   A a;
   std::function<void(int, int)> fr =
         std::bind(&A::output, &a, std::placeholders::_1
, std::placeholders::_2);
   fr(1, 2);      // 输出: 1 2

   std::function<int&(void)> fr_i =std::bind(&A::i_, &a);
   fr_i() = 123;
   std::cout << a.i_ << std::endl; // 输出: 123

   return 0;
}

fr的类型是std::function<void(int, int)>。我们通过使用std::bind,将A的成员函数output的指针和a绑定,并转换为一个仿函数放入fr中存储。

之后,std::bind将A的成员i_的指针和a绑定,返回的结果被放入std::function<int&(void)>中存储,并可以在需要时修改访问这个成员。

现在,通过std::function和std::bind的配合,所有的可调用对象均有了统一的操作方法。

下面再来看几个std::bind的使用例子。

1.使用bind简化和增强bind1st和bind2nd
其实bind简化和增强了之前标准库中bind1st和bind2nd,它完全可以替代bind1s和bind2st,并且能组合函数。我们知道,bind1st和bind2nd的作用是将一个二元算子转换成一个一元算子,代码如下:

// 查找元素值大于10的元素的个数
int count = std::count_if(coll.begin(), coll.end(),
std::bind1st(less<int>(), 10));
// 查找元素之小于10的元素
int count = std::count_if(coll.begin(), coll.end(),
std::bind2nd(less<int>(), 10));

本质上是对一个二元函数less<int>的调用,但是它却要分别用bind1st和bind2nd,并且还要想想到底是用bind1st还是bind2nd,用起来十分不便。

现在我们有了bind,就可以以统一的方式去实现了,代码如下:

using std::placeholders::_1;
// 查找元素值大于10的元素的个数
int count = std::count_if(coll.begin(),
coll.end(),std::bind(less<int>(), 10, _1));
// 查找元素之小于10的元素
int count = std::count_if(coll.begin(),
coll.end(),std::bind(less<int>(), _1, 10));

这样就不用关心到底是用bind1st还是bind2nd,只需要使用bind即可。

2.使用组合bind函数

bind还有一个强大之处就是可以组合多个函数。假设要找出集合中大于5小于10的元素个数应该怎么做呢?

首先,需要一个用来判断是否大于5的功能闭包,代码如下:

std::bind(std::greater<int>(), std::placeholders::_1, 5);

这里std::bind返回的仿函数只有一个int参数。当输入了这个int参数后,输入的int值将直接和5进行大小比较,并在大于5时返回true。

然后,我们需要一个判断是否小于10的功能闭包:

std::bind(std::less_equal<int>(),std::placeholders::_1,10);

有了这两个闭包之后,只需要用逻辑与把它们连起来:

using std::placeholders::_1;
std::bind(std::logical_and<bool>(),
std::bind(std::greater<int>(), _1, 5),
std::bind(std::less_equal<int>(), _1, 10));
然后就可以复合多个函数(或者说闭包)的功能:
using std::placeholders::_1;
// 查找集合中大于5小于10的元素个数
auto f = std::bind(std::logical_and<bool>(),
std::bind(std::greater<int>(), _1, 5),
std::bind(std::less_equal<int>(), _1, 10));
int count = std::count_if(coll.begin(), coll.end(), f);

 

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:1.3 功能
下一篇:1.5 小结
相关文章
图文推荐
JavaScript网页动画设
1.9 响应式
1.8 登陆页式
1.7 主题式
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站