本着看懂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個參數*/);
完結,但願對你們有幫助。