本着看懂boost::bind总体流程的角度出发,将boost::bind的源码精简贴出,去除了全部多余部分,只在说明问题,错误在所不免,但愿你们勿喷。 app
bind_t对象就是boost::bind方法的返回值,它保存了F和L的值。其中F为函数指针类型,L为listN类型(N的范围为0-9),它将保存用户调用boost::bind方法时传入的绑定参数。例如: void fun_1(int left, int right){//dosomething} boost::bind(&fun_1, 100, 200); 此时,将产生一个list2对象保存在生成的bind_t对象中,list2中包含100,200. 不是listN吗?怎么变成了list2呢,这就是大牛们写了那么一大堆泛型代码的做用了,它是在编译阶段,由强大的编译器经过类型检查推断出来的。下面展现bind_t源码:主要是由bind.hpp和bind_template.hpp提取出来的。 函数
template<class R, class F, class L> class bind_t { public: typedef bind_t this_type; bind_t(F f, L const & l): f_(f), l_(l) {} typedef typename result_traits::type result_type; result_type operator()() { list0 a; BOOST_BIND_RETURN l_(type(), f_, a, 0); } templateresult_type operator()(A1 & a1) { list1 a(a1); BOOST_BIND_RETURN l_(type(), f_, a, 0); } template result_type operator()(A1 & a1, A2 & a2) { list2 a(a1, a2); BOOST_BIND_RETURN l_(type(), f_, a, 0); } ... template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8) { list8 a(a1, a2, a3, a4, a5, a6, a7, a8); BOOST_BIND_RETURN l_(type(), f_, a, 0); } };
你们能够清晰的看到bind_t对象中只有一个构造函数,和多个operator()(**)重载函数,这意味着什么?这意味着,每一个bind_t都有多个operator()(**)方法。因此你能够这样:
boost::bind(&fun_1, 100, 200)();
boost::bind(&fun_1, 100, 200)(100,200);
boost::bind(&fun_1, 100, 200)(100,200,300,400);
boost::bind(&fun_1, 100, 200)(100,200,300,400,..,900);
都不会报错,可是若是你这样:
boost::bind(&fun_1, 100, _1)();//报错,
会提示找不到list0的operator[](boost::arg)方重载
boost::bind(&fun_1, 100, _1)(100);//正确
boost::bind(&fun_1, 100, 200)();//正确 this
??为何呢?你们能够先看看对应的bind_t中operator()(**)方法,相信你们可能只能那么一点点了,不过要想真正的想通,咱们还得看另一组类,listN. 我只列举list0,list1,list2, 其他的list3-list9相信你们能够触类旁通。 spa
class list0 { public: list0() {} template<class T> T & operator[] (_bi::value<T> & v) const { return v.get(); } template<class R, class F, class A> R operator()(type<R>, F & f, A &, long) { return unwrapper<F>::unwrap(f, 0)(); } };
template< class A1 > class list1: private storage1< A1 > { private: typedef storage1< A1 > base_type; public: explicit list1( A1 a1 ): base_type( a1 ) {} A1 operator[] (boost::arg<1>) const { return base_type::a1_; } A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } template<class T> T & operator[] ( _bi::value<T> & v ) const { return v.get(); } template<class F, class A> void operator()(type<void>, F & f, A & a, int) { unwrapper<F>::unwrap(f, 0)(a[base_type::a1_]); }
template< class A1, class A2 > class list2: private storage2< A1, A2 > { private: typedef storage2< A1, A2 > base_type; public: list2( A1 a1, A2 a2 ): base_type( a1, a2 ) {} A1 operator[] (boost::arg<1>) const { return base_type::a1_; } A2 operator[] (boost::arg<2>) const { return base_type::a2_; } A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } A2 operator[] (boost::arg<2> (*) ()) const { return base_type::a2_; } template<class T> T & operator[] (_bi::value<T> & v) const { return v.get(); } template<class F, class A> void operator()(type<void>, F & f, A & a, int) { unwrapper<F>::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]); } };
你们能够看到每一个listN类里都有一组operator[] 和 operator()方法,其中operator()就是在bind_t的operator()中被调用的方法(红色背景标注的),而在listN的operator()中只有一句很是重要,就是他完成了用户绑定参数和函数调用时实参之间的转化,下面咱们仍是拿上面那个错误的例子分析一下: 指针
boost::bind(&fun_1, 100, _1)();//报错, code
经上面的分析你们能够知道以下信息: 对象
F = void (*)(int,int) ci
L = list2<int,boost::arg<1> >//这个不许确,你们看源代码,意思知道就好了 get
list2<int,int>::base_type::a1_ = 100 编译器
list2<int,int>::base_type::a2_ = _1;
将会调用bind_t对象的方法,以下:
result_type operator()() { list0 a; BOOST_BIND_RETURN l_(type(), f_, a, 0); }接着调用list2对象的方法,以下:
template<class F, class A> void operator()(type<void>, F & f, A & a, int) { unwrapper<F>::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]); }
此时 f_ = &fun_1, a = list0
用实参替换,简化可得:
f(a[100], a[_1]);
再进一步, 调用list0的operator[]的方法:
a[100]调用的方法声明以下:
template<class T> T & operator[] (_bi::value<T> & v) const { return v.get(); }
所以返回100,进一步简化:
f(100, a[_1]);
这时问题出现了,list0中没有对应于a[_1],也就是相似于下面方法的重载,固然会报错了!!
A1 operator[] (boost::arg<1>) const { return base_type::a1_; }
至此,问题解答完毕,再来总结一下:
boost::bind(fun, arg1, arg2, ...,argN)(a1, a2,...,aM);
一、会产生两个listN对象,第一个listN对应于arg1,arg2实参个数,arg1,arg2的个数必须和fun函数声明一直,不然报错。第二个listN对象由a1,a2的个数决定。
二、若是arg1,arg2为占位符,那么必须保证 对应于a1,a2生成的listN对象中必须存在其对应的operator[](boost::argv<N>)的重载函数,不然确定报错!如何保证呢, 其实很简单。M的个数>= arg1-argN中占位符的最大值.
举个例子:
boost::bind(fun, 100, _1)(/*注意此时,至少要生成list1,就是至少要传一个参数*/);
boost::bind(fun, 100, _1, _9)(/*注意此时,至少要生成list9,就是至少要传9个参数*/);
完结,但愿对你们有帮助。