boost::bind函数原理和使用

1.看BOOST_BIND源码推导的具体过程:

(1). bind是一个函数,返回值是一个 bind_t 对象,然后再调用bind_t对象的 operator() 函数

(2).看下面的代码,list_av_2实际上是一个包装类,list_type的实际值见下面的代码:

template<class F, class A1, class A2>
    _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_2<A1, A2>::type>
    BOOST_BIND(F f, A1 a1, A2 a2)
{
    typedef typename _bi::list_av_2<A1, A2>::type list_type;
    return _bi::bind_t<_bi::unspecified, F, list_type> (f, list_type(a1, a2));
}

 

template<class A1, class A2> struct list_av_2
{
    typedef typename add_value<A1>::type B1;
    typedef typename add_value<A2>::type B2;
    typedef list2<B1, B2> type;
};

所以bind_t对象的成员有:f 和 listN(这里的N指的是参数的个数)

(3).在调用 bind_t 的operator()函数的时候,又会有一个listN,所以一共有两个listN。

在下面的代码中又会发现一个变量a,它也是listN

template<class A1, class A2> result_type operator()(A1 & a1, A2 & a2)
    {
        list2<A1 &, A2 &> a(a1, a2);
        BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
    }

 

(4)在bind_t的operator() 函数里面又调用了 listN的 operator函数:

下面两个listN同时出现了,一个以this的形式出现,一个以 变量a的形式出现:

注意:unwrap有很多重载函数

template<class R, class F, class A> R operator()(type<R>, F & f, A & a, long)
    {
        return unwrapper<F>::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]);
    }

(5)然后又会调用listN的operator[]函数,这里需要注意的是operator[]会有很多重载函数

operator[]的作用是,右站位符得到具体的参数值。

 

 

2.bind函数的应用举例:

(1)对于普通函数

void f(int a, int b)

{

    cout<<a<<b<<endl;

}

向它绑定参数:

bind(f,3,4)();  //相当于f(3,4)

bind(f,_1,3)(4);//相当于 f(4,3), _1在这里是占位符(plave holder), 它对应与第二个括号里面的参数,_1表示第一个参数,_2表示第二个参数,一共可以到_9

bind(f,_2,_1)(3,4); //相当于f(4,3), 可以看出这里占位符的顺序是可以变的。

 

更具上面的代码分析,因为函数的参数个数是 bind_t 对象的 listN决定的,所以第二个 listN的个数可以有多个,只要符合要求就行:

ex:

bind(f,_1,_3)(1,2,3,4); //f(1,3)

bind(f, _1,_1)(1,2,3);//f(1,1)


int f1()
{
    return 1;
}

int a = boost::BOOST_BIND(f1)();

 

(2).结构体或者类的成员函数的绑定:

绑定operator()函数:

struct Func {
  void operator()(int x) {
   cout << x << endl;
  }
 } f;
绑定的时候可能要指出返回值的类型:
 boost::bind<void >(f, 3)();   //指出返回值的类型 void

绑定其它成员函数:

 struct A {
  void func(int x, int y) {
   cout << x << "," << y << endl;
  }
 };
 
 A a;  
 A* pa = new A; //指针
 boost::shared_ptr<A> ptr_a(pa);  //智能指针.
 
现在 要向像 A::func 这样的非静态成员函数绑定. 
若A::func有n个参数, 则 bind 要有 n+2 个参数: 指向成员函数fun的指针, 绑定到this的对象, n个参数.
如:  
 boost::bind(&A::func, a , 3, 4)();     //输出 3, 4
 boost::bind(&A::func, pa , 3, 4)();    //输出 3, 4
 boost::bind(&A::func, ptr_a , 3, 4)(); //输出 3, 4
同样可以用 _1 这样的占位符. 如:
 boost::bind(&A::func, _1, 3, 4)(ptr_a);//输出 3, 4


和function联合使用:

boost::function<void*(void*)> threadRoutine;
threadRoutine = boost::BOOST_BIND(&XServer::ServerRoutine,this,_1);

 

(3)绑定类的成员变量,这个在排序的时候比较有用

有个类如下. 记录人的信息:
 class Personal_info {
  string name_;
  int age_;
 public:
  int get_age();
  string name();
 };

 vector<Personal_info> vec; 
 ...
现在要对 vec 排序. 可以用 bind 函数做一个比较谓词
 std::sort(  
  vec.begin(),  
  vec.end(),  
  boost::bind( 
   std::less<int>(),    
   boost::bind(&personal_info::age,_1),     //_1 占位符是 sort 中调用比较函数时的第一个参数.
   boost::bind(&personal_info::age,_2)));   //_2 占位符是 sort 中调用比较函数时的第二个参数.

 

绑定到map的成员变量:

绑定到成员变量

有:
 map<int, string> my_map;
 my_map[0]="Boost";my_map[1]="Bind";
现在要输出所有元素的 second 成员. 也就是输出这些字符串. 其中的打印函数如下:
 void print_string(const string& s) {  
  std::cout << s << '/n';
 }
则可以:
 for_each(  
  my_map.begin(),  
  my_map.end(),  
  boost::bind(
   &print_string, 
   boost::bind(&std::map<int,std::string>::value_type::second,_1)
   )
  );

 

(4)函数组合

假如有:
 vector<int> ints;
 ...
想用 std::count_if() 来求ints中有多少是 >5 且 <=10 的. 这在常规代码中通常就要写一个函数来实现这个谓词:
 if (i>5 && i<=10) ...
现在用bind则可以:
 std::count_if(  
  ints.begin(),  ints.end(),  
  boost::bind(    
   std::logical_and<bool>(),    
   boost::bind(std::greater<int>(),_1,5),    
   boost::bind(std::less_equal<int>(),_1,10)));

 

(5)绑定引用和指针

有函数:
void f(int & x) { ++x; }
然后:
int n = 0;
bind(&f, n)();    //我们希望 n==1 . 但实际上没有这样...

要避免这种对象复制.  而 要bind得到的函数对象保存实参的引用语义. 可以:
使用 boost::ref ()  或 boost::cref () 如
bind(&f, ref(n) )();        //OK,  执行后 n==1

如果是绑定一个对象到它的成员函数上. 如:
A a;
bind(&A::fun, a );       //则保存的是 a对象的拷贝.
要避免这种拷贝. 除了上面提到的 ref() 外, 也可以:
bind(&A::fun, &a );      //用指针.  反正用对象和用指针都可以. 而用指针可以避免对象拷贝的问题. 

(6)绑定函数:

bind () 的第一个参数——被绑定函数——是不被求值的. 如下例:

typedef void (*pf)(int);
std::vector<pf> v;  //v中有一些函数指针.
std::for_each(v.begin(), v.end(), bind(_1, 5) );    //想实现 _1(5);  这样的调用. 但这样不行!

正确的做法是借助 boost::apply 模板(来自boost/bind/apply.hpp).   
apply也是一个函数对象. 它的作用如下:
apply<void> a;   //模板参数为函数对象的返回值类型.
a(x);       //相当于调用 x();
a(x, y);    //相当于调用  x(y);
a(x, y, z);  //相当于调用 x(y, z);
所以错误的bind应该写为:
std::for_each(v.begin(), v.end(), bind(apply<void>(), _1, 5));

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值