工作中要用到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的用法总结。