by:武龙飞
工作中要用到boost库,我的学习习惯是在学习新的知识的时候,将整个知识点的历史和发展现状过一遍。这样既能激发学习兴趣,同时对于知识点的记忆和学习能形成一个完整的系统结构。boost库最新版本是1.47,今天主要总结boost库里一个常用的函数bind,由于之前从来没有用过这个函数,对这个函数的一些妙用也不甚了解。
我对bind函数的理解是,bind现在最大支持九个参数,通过对bind传递不同的参数,最后返回一个新的函数指针,通过这个函数指针的调用变相的产生新的函数。我先用普通方法简单模拟一下,大概说明白bind 的原理就行。代码如下:
- #include "stdafx.h"
- #include <iostream>
- #include "boost/bind.hpp"
- #include "boost/function.hpp"
- using namespace std;
- void PrintHello(int i)
- {
- cout<<"hello, world.\n";
- }
- void CallFuntion(void (*f)(int), int i)
- {
- f(i);
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- CallFuntion(PrintHello, 2);
- getchar();
- return 0;
- }
这个就是通过传递函数PrintHello的函数指针给CallFuntion函数,当然了,有人说直接调用PrintHello多省事,呵呵,说的没错,看看下面bind的几种用法吧。
1、bind构造普通函数
- #include "stdafx.h"
- #include <iostream>
- #include "boost/bind.hpp"
- #include "boost/function.hpp"
- using namespace std;
- void PrintHello(int i)
- {
- cout<<"hello, world.\n";
- }
- void CallFuntion(void (*f)(int), int i)
- {
- f(i);
- }
- void CallBindFunction(boost::function<void (void)> f)
- {
- f();
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- CallFuntion(PrintHello, 2);
- CallBindFunction(boost::bind(PrintHello, 2));
- getchar();
- return 0;
- }
看见区别了吧,通过配合boost里的function函数,不就可以实现函数变参了,这就是bind的一种妙用。
2、bind函数调整参数
- #include "stdafx.h"
- #include <iostream>
- #include "boost/bind.hpp"
- #include "boost/function.hpp"
- using namespace std;
- int Sum2(int i, int j)
- {
- return i + j;
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- cout<<Sum2(1, 2)<<endl; // Sum2(x, y);
- boost::function<int (int, int)> f11 = boost::bind(Sum2, _1, _1); // Sum2(x, x);
- cout<<f11(1, 2)<<endl;
- boost::function<int (int, int)> f21 = boost::bind(Sum2, _2, _1); // Sum2(y, x);
- cout<<f21(1, 2)<<endl;
- boost::function<int (int, int)> f12 = boost::bind(Sum2, _2, _2); // Sum2(y, y);
- cout<<f12(1, 2)<<endl;
- boost::function<int (int, int)> f13 = boost::bind(Sum2, _1, 3); // Sum2(x, 3);
- cout<<f13(1, 2)<<endl;
- getchar();
- return 0;
- }
这就是通过bind函数构造出不同参数的函数,是不是大大加大了代码的复用性和易用性。同时可以在bind的参数里设置构造的新函数默认值。
3、函数对象
- #include "stdafx.h"
- #include <iostream>
- #include "boost/bind.hpp"
- #include "boost/function.hpp"
- #include "boost/ref.hpp"
- using namespace std;
- struct F
- {
- int s;
- int operator()(int i){ return s += i;}
- bool operator()(bool b){ return b;}
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- F f = {0};
- int arry[3] ={1, 2, 3};
- //boost::function<int (int)> sum = boost::bind(boost::ref(f), _1);
- boost::function<int (int)> sum = boost::bind<int>(boost::ref(f), _1);
- for_each(arry, arry + 3, sum);
- assert(f.s != 6);
- return 0;
- }
这里有两个知识点,一个是bind构造的函数要表明返回类型,boost文档给出的解释是: 没有 typeof操作符,返回类型无法推导。其实我们自己也很容易看出来,对于上面申明的两个操作符重载,没有返回类型确实无法分辨。第二个知识点是,引用的问题,假如不添加引用符号ref的话,默认会复制一个新的函数对象,这样的话,前面定义的f的s值不会改变。
4、成员函数
- #include "stdafx.h"
- #include <iostream>
- #include "boost/bind.hpp"
- #include "boost/function.hpp"
- #include "boost/ref.hpp"
- #include "boost/shared_ptr.hpp"
- using namespace std;
- struct X
- {
- void f(int count)
- {
- for (int i = 0; i < count; ++i)
- {
- cout<<"hello,world.\n";
- }
- }
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- X x;
- boost::shared_ptr<X> p(new X);
- boost::function<void (int)> PrintHello1 = boost::bind(&X::f, boost::ref(x), _1); // x.f(i)
- PrintHello1(1);
- boost::function<void (int)> PrintHello2 = boost::bind(&X::f, &x, _1); // (&x)->f(i)
- PrintHello2(2);
- boost::function<void (int)> PrintHello3 = boost::bind(&X::f, x, _1); // (internal copy of x).f(i)
- PrintHello2(3);
- boost::function<void (int)> PrintHello4 = boost::bind(&X::f, p, _1); // (internal copy of p).f(i)
- PrintHello2(4);
- return 0;
- }
这里注意的是第三种方式和第四种方式,第三种方式里的x将被拷贝,如果x数据结构比较大的话,效率上讲就非常低了,需要注意。第四种也是拷贝,但这里还申明为shared_ptr类型,意思是在出了限定域内不会释放,这boost文档里给出的例子。没有别的意思,就是见到后注意下就行。
bind基本就这几种用法,还有一些比较巧妙的用法,比如说将bind返回值当作参数传递给bind嵌套用法,还有将function<void (void)> 类型申明为成员函数。有兴趣的话可以看boost文档,或者九天雁翱的关于bind的用法总结。