Boost::Bind 源碼實現簡化版

本着看懂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個參數*/);

完結,但願對你們有幫助。

相關文章
相關標籤/搜索