boost::function和boost::bind 介绍

一. boost::function介绍

原文:http://www.cnblogs.com/sld666666/archive/2010/12/16/1907591.html

    本片文章主要介绍boost::function的用法。 boost::function 就是一个函数的包装器(function wrapper),用来定义函数对象。

1.  介绍

    Boost.Function 库包含了一个类族的函数对象的包装。它的概念很像广义上的回调函数。其有着和函数指针相同的特性但是又包含了一个调用的接口。一个函数指针能够在能以地方被调用或者作为一个回调函数。boost.function能够代替函数指针并提供更大的灵活性。

2. 使用

    Boost.Function 有两种形式:首选形式和便携式形式, 其语法如下:

首选形式 便携式形式
boost::function<float(int x, int y)>f boost::function2<float, int, int>f

但是便携式形式不是所有的编译器都支持的, 所以这里我只介绍首选形式。

2.1 普通函数

    我们可以看下如下的例子: 

1 void do_sum(int *values, int n) 
2 { 
3 int sum(0);
4 for (int i = 0; i < n; ++i) 
5 { 
6 sum += values[i]; 
7 } 
8 cout << sum << endl; 
9 };
10 int _tmain(int argc, _TCHAR* argv[]) 
11 { 
12 boost::function<void(int *values, int n)> sum; 
13 sum = &do_sum;
14 int a[] = {1,2,3,4,5}; 
15 sum(a, 5);
16 return 0; 
17 }

  sum 可以理解为一个广义的函数对象了,其只用就是保存函数do_sum, 然后再调用之。

2.2 成员函数

    在很多系统中, 对于类的成员函数的回调需要做特殊处理的。这个特殊的处理就是“参数绑定”。当然这个超出了我们讨论的范围了。 boost::function对于成员函数的使用可以看下如下代码:

1 class X{ 
2 public: 
3 int foo(int a) 
4 { 
5 cout << a <<endl; 
6 return a; 
7 } 
8 };
9 int _tmain(int argc, _TCHAR* argv[]) 
10 { 
11 boost::function<int(X*, int)>f;
12 f = &X::foo;
13 X x; 
14 f(&x, 5);
15 return 0; 
16 }

    我们发现, 对类的成员函数的对象化从语法是没有多大的区别。

3. 一个典型的例子

    上面的几个例子没有体现出boost::function的作用来, 这里在写一个例子。比如当程序执行到某一处的时候想绑定某一个函数, 但是不想立即执行, 我们就可以声明一个函数对象,给此对象绑定相应的函数, 做一些其他事情,然后再来执行绑定的函数, 代码如下:

1 void print(int a) 
2 { 
3 cout << a << endl; 
4 }
5 typedef boost::function<void (int)> SuccessPrint;
6 int _tmain(int argc, _TCHAR* argv[]) 
7 { 
8 vector<SuccessPrint> printList;
9 SuccessPrint printOne = boost::bind(print, _1); 
10 printList.push_back(printOne); 
11 SuccessPrint printTwo = boost::bind(print, _1); 
12 printList.push_back(printTwo); 
13 SuccessPrint printThree = boost::bind(print, _1); 
14 printList.push_back(printTwo); 
15 // do something else
16 for (int i = 0; i < printList.size(); ++i) 
17 printList.at(i)(i);
18 return 0; 
19 }

     上述代码中首先把声明一个函数对象 typedef boost::function<void (int)> SuccessPrint, 然后把print绑定到斥对象中, 放入vector中, 到最后才来执行这print()函数。

二. boost::bind介绍

        最近在几经波折之后,终于对于boost::bind有点理解了。对于习惯了其他语言的人来说,boost::bind是个挺神奇的东西,它可以将你的方法适配成任何其他的方法。其实这得益于c++的模板以及操作符重载,去看boost::bind的实现就会发现它是一个有n多重载的函数,这些重载主要是为了适应函数的参数个数。

       其实boost::bind的原理是函数对象,而函数对象就是一个重载了()操作符的对象,这样我们就可以像调用一个方法一样来调用一个类上的这个操作符,比如a(),其实你是在调用a这个对象的()方法,而不是调用一个叫a的方法。

       一般来说boost::bind有两种方式的调用,一种是对自由方法,也取非类方法, 一种是对类方法。

       对自由方法来说,直接boost::bind(函数名, 参数1,参数2,...)

       对类方法来说,直接boost::bind(&类名::方法名,类实例指针,参数1,参数2)

       这里需要额外注意的问题是,函数对象也可以像自由方法一样被bind,而boost::function也是一种函数对象。

       接下来我们需要注意什么情况下需要用_1, _2这样的参数。

       举个例子

       void test(int a, int b, int c)

       boost::bind(test, 1, _1, _2)得到一个函数对象b,当我们调用b(3,4)时,相当于调用test(1,3,4)

       boost::bind(test, _2, 3, _1)得到一个函数对象b,当我们调用b(3,4)时,相当于调用test(4,3,3)

       看明白了没有?你实际上可以指定一些常量和一些占位符进去,_x这样的就是占位符,_1表示实际调用时的参数位置,也即b(3,4)时_1代表3,_2代表4 

       当然你也可以将所有的参数都指定,比如boost::bind(test,1,2,3),那么在调用b()时就相当于调用test(1,2,3)

       需要注意的一点是,boost::bind里的参数个数一定要与被bind的函数相同,否则这个函数对象就无法生成了,编译器会抱怨一堆信息,如果你仔细看的话,它是在告诉你,没有这样的函数,你实际的函数是....,这是使用c++很杯具的一点,当遇到模板时,一旦报错,那些信息直接可以令人崩溃。

       在asio中,boost::bind被大量使用,原因是异步的情况下,每个函数的调用是独立的,它的所有信息应该包含在它的调用,也即函数对象中。因此asio中有大量的模板,如果在这种情况下你想要使用虚函数或者继承来写框架的话,会是一件很杯具的事情,在碰了很多次壁之后,我发现其实很多情况下我并不需要纯虚函数,我需要的只是一个函数指针,或者函数对象而已。

原文地址:https://www.cnblogs.com/cj2014/p/4615813.html