boost之bind源码剖析

来源:互联网 发布:加入淘宝联盟收费吗 编辑:程序博客网 时间:2024/05/21 17:43
1.为什么使用bind
引用《Beyond the C++ Standard Libarary: An introduction to Boost》中的原文,如下:
a. 使函数和函数对象适用于标准库算法
b. 使用一致的语汇法创建绑定器binder
c. 强大的函数组合(functional composition)
2. 使用bind的例子,请参考《Beyond the C++ Standard Libarary: An introduction to Boost》给出的例子

3.工作机制:《Beyond the C++ Standard Libarary: An introduction to Boost》也给出了bind的简单工作机制,即simple_bind返回simple_bind_t对象,simple_bind_t对象调用operator()。

4.本文重点给出boost库中bind的具体实现,把bind完全呈现在大家面前,跑到帷幕之后,观察bind是如何工作的。
4.1. 代码组织:boost::bind的源码主要集中在bnd.hpp/bind_template.hpp中,想搞清楚bind的运行机制,这两个文件足矣。

角色1:各种参数占位符,对于bind来说,接受的占位符有三种value<type>, arg<N>, reference_wrapper<type>
比如bind(plus<int>(), _1, 1);则 _1对应于arg<1>,而1将转换成value<int>(1),即bind的第三个参数类型为value<int>
比如bind(minus<int>(), bind(plus<int>(), _1, 1), _2);  由于bind(plus<int>(), _1, 1)的返回类型为bind_t,因此这里最外层bind的第二个参数的类型为bind_t,这里是根据里层的bind的返回值的类型来进行推演的,使用了intermediate function template手法,即
template<typename T>
void return_type_trait(T t)
{
}

// 对于以下函数foo/bar,return_type_trait能够粹取出其返回值类型
int foo()
{
  
return 0;
}


std::
string bar()
{
  
return std::string();
}


return_type_trait(foo()); 
// 可以推演出T为int
return_type_trait(bar()); // 推演到T为std::string

回到正题,首先给出bind各种“占位符”的实现:

template<class T> class value // 用于bind参数的“早绑定”,即实参是在一开始就做为参数传递给bind作为参数
{
public:
    value(T 
const & t): t_(t) {}
    T 
& get() return t_; } // 后面从实参列表中拿数据时都是直接从value<T>的对象中直接拿出来
    T 
const & get() const return t_; }
    
bool operator==(value const & rhs) const
    
{
        
return t_ == rhs.t_;
    }

private:
    T t_;
}
;

template
<int I> // 用于bind参数的“后绑定”,正儿八经的占位符
struct arg{};

template
<class T> class reference_wrapper

public:
    typedef T type;
    
explicit reference_wrapper(T& t): t_(&t) {}
    
operator T& () const return *t_; }
    T
& get() const return *t_; }
    T
* get_pointer() const return t_; }
private:
    T
* t_;
}
;

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
<R, F>::type result_type;
    result_type 
operator()()
    
{
        list0 a;
        
return l_(type<result_type>(), f_, a, 0);
    }


    result_type 
operator()() const
    
{
        list0 a;
        
return l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1> result_type operator()(A1 & a1)
    
{
        list1
<A1 &> a(a1);
        
return l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1> result_type operator()(A1 & a1) const
    
{
        list1
<A1 &> a(a1);
        
return l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1> result_type operator()(A1 const & a1)
    
{
        list1
<A1 const &> a(a1);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1> result_type operator()(A1 const & a1) const
    
{
        list1
<A1 const &> a(a1);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2> result_type operator()(A1 & a1, A2 & a2)
    
{
        list2
<A1 &, A2 &> a(a1, a2);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2> result_type operator()(A1 & a1, A2 & a2) const
    
{
        list2
<A1 &, A2 &> a(a1, a2);
        
return  l_(type<result_type>(), f_, a, 0);
    }



    template
<class A1, class A2> result_type operator()(A1 const & a1, A2 & a2)
    
{
        list2
<A1 const &, A2 &> a(a1, a2);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2> result_type operator()(A1 const & a1, A2 & a2) const
    
{
        list2
<A1 const &, A2 &> a(a1, a2);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2> result_type operator()(A1 & a1, A2 const & a2)
    
{
        list2
<A1 &, A2 const &> a(a1, a2);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2> result_type operator()(A1 & a1, A2 const & a2) const
    
{
        list2
<A1 &, A2 const &> a(a1, a2);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2> result_type operator()(A1 const & a1, A2 const & a2)
    
{
        list2
<A1 const &, A2 const &> a(a1, a2);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2> result_type operator()(A1 const & a1, A2 const & a2) const
    
{
        list2
<A1 const &, A2 const &> a(a1, a2);
        
return  l_(type<result_type>(), f_, a, 0);
    }
 

    template
<class A1, class A2, class A3> result_type operator()(A1 & a1, A2 & a2, A3 & a3)
    
{
        list3
<A1 &, A2 &, A3 &> a(a1, a2, a3);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3> result_type operator()(A1 & a1, A2 & a2, A3 & a3) const
    
{
        list3
<A1 &, A2 &, A3 &> a(a1, a2, a3);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4)
    
{
        list4
<A1 &, A2 &, A3 &, A4 &> a(a1, a2, a3, a4);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4) const
    
{
        list4
<A1 &, A2 &, A3 &, A4 &> a(a1, a2, a3, a4);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4, class A5> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5)
    
{
        list5
<A1 &, A2 &, A3 &, A4 &, A5 &> a(a1, a2, a3, a4, a5);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4, class A5> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5) const
    
{
        list5
<A1 &, A2 &, A3 &, A4 &, A5 &> a(a1, a2, a3, a4, a5);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4, class A5, class A6> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6)
    
{
        list6
<A1 &, A2 &, A3 &, A4 &, A5 &, A6 &> a(a1, a2, a3, a4, a5, a6);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4, class A5, class A6> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6) const
    
{
        list6
<A1 &, A2 &, A3 &, A4 &, A5 &, A6 &> a(a1, a2, a3, a4, a5, a6);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4, class A5, class A6, class A7> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7)
    
{
        list7
<A1 &, A2 &, A3 &, A4 &, A5 &, A6 &, A7 &> a(a1, a2, a3, a4, a5, a6, a7);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4, class A5, class A6, class A7> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7) const
    
{
        list7
<A1 &, A2 &, A3 &, A4 &, A5 &, A6 &, A7 &> a(a1, a2, a3, a4, a5, a6, a7);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8)
    
{
        list8
<A1 &, A2 &, A3 &, A4 &, A5 &, A6 &, A7 &, A8 &> a(a1, a2, a3, a4, a5, a6, a7, a8);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8) const
    
{
        list8
<A1 &, A2 &, A3 &, A4 &, A5 &, A6 &, A7 &, A8 &> a(a1, a2, a3, a4, a5, a6, a7, a8);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8, A9 & a9)
    
{
        list9
<A1 &, A2 &, A3 &, A4 &, A5 &, A6 &, A7 &, A8 &, A9 &> a(a1, a2, a3, a4, a5, a6, a7, a8, a9);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9> result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8, A9 & a9) const
    
{
        list9
<A1 &, A2 &, A3 &, A4 &, A5 &, A6 &, A7 &, A8 &, A9 &> a(a1, a2, a3, a4, a5, a6, a7, a8, a9);
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A> result_type eval(A & a)
    
{
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class A> result_type eval(A & a) const
    
{
        
return  l_(type<result_type>(), f_, a, 0);
    }


    template
<class V> void accept(V & v) const
    
{
        visit_each(v, f_, 
0);
        l_.accept(v);
    }


    
bool compare(this_type const & rhs) const
    
{
        
return ref_compare(f_, rhs.f_, 0&& l_ == rhs.l_;
    }


private:
    F f_;
    L l_;
}
;

有了以上用于bind的“占位符”,我们接着看这些“占位符”是怎么被实际的参数所取代的。

角色2. bind如何构造bind_t对象,仍以接受两个占位符的bind为例

template<class R, class F, class A1, class A2>
  bind_t
<R, F, typename  list_av_2<A1, A2>::type>
    bind(boost::type
<R>, F f, A1 a1, A2 a2)
{
    typedef typename  list_av_2
<A1, A2>::type list_type;
    
return  bind_t<R, F, list_type> (f, list_type(a1, a2));
}
即将传递进来的占位符类型通过捆绑成一个更大的类型list_av_X,具体定义如下

template<class A1, class A2> struct list_av_2
{
    typedef typename add_value
<A1>::type B1;
    typedef typename add_value
<A2>::type B2;
    typedef list2
<B1, B2> type;
}
;
// 其中add_value的定义又如下:
template<class T> struct add_value
{
    typedef  value
<T> type;
}
;

template
<class T> struct add_value< value<T> >
{
    typedef  value
<T> type;
}
;

template
<class T> struct add_value< reference_wrapper<T> >
{
    typedef reference_wrapper
<T> type;
}
;

template
<int I> struct add_value< arg<I> >
{
    typedef  arg
<I> type;
}
;

template
<int I> struct add_value< arg<I> (*) () >
{
    typedef  arg
<I> (*type) ();
}
;

template
<class R, class F, class L> struct add_value< bind_t<R, F, L> >
{
    typedef bind_t
<R, F, L> type;
}
;

bind.hpp中定义了模板类listN,N从0~9,即bind接受的“占位符”个数介于0-9之间
bind返回的是bind_t,通过将传递进来的占位符进行捆绑,变成list_av_x,其中x为0-9
如果传给bind的参数是_1,则其类型是arg<1>,如果传递进来的参数是1,则其类型
为value<int>,类型还可以为bind_t,将这些类型捆绑在一起,就成了bind模板函数的
第三个模板参数L,仍以上面的例子来讲,因此L的类型可推演为list2<arg<1>, value<int> >

角色3: listN

template<class A1, class A2> class list2
{
public:
    list2(A1 a1, A2 a2): a1_(a1), a2_(a2) 
{}
    A1 
operator[] (arg<1>const return a1_; }
    A2 
operator[] (arg<2>const return a2_; }
    A1 
operator[] (arg<1> (*) ()) const return a1_; }
    A2 
operator[] (arg<2> (*) ()) const return a2_; }

    template
<class T> T & operator[] (value<T> & v) const return v.get(); }
    template
<class T> T const & operator[] (value<T> const & v) const return v.get(); }
    template
<class T> T & operator[] (reference_wrapper<T> const & v) const return v.get(); }
    template
<class R, class F, class L> typename result_traits<R, F>::type operator[] (bind_t<R, F, L> & b) const return b.eval(*this); }
    template
<class R, class F, class L> typename result_traits<R, F>::type operator[] (bind_t<R, F, L> const & b) const return b.eval(*this); }

    template
<class R, class F, class A> R operator()(type<R>, F & f, A & a, long)
    
{
        
return unwrap(&f, 0)(a[a1_], a[a2_]);
    }


    template
<class R, class F, class A> R operator()(type<R>, F const & f, A & a, longconst
    
{
        
return unwrap(&f, 0)(a[a1_], a[a2_]);
    }


    template
<class F, class A> void operator()(type<void>, F & f, A & a, int)
    
{
        unwrap(
&f, 0)(a[a1_], a[a2_]);
    }


    template
<class F, class A> void operator()(type<void>, F const & f, A & a, intconst
    
{
        unwrap(
&f, 0)(a[a1_], a[a2_]);
    }


    template
<class V> void accept(V & v) const
    
{
        vist_each(v, a1_, 
0);
        vist_each(v, a2_, 
0);
    }


    
bool operator==(list2 const & rhs) const
    
{
        
return ref_compare(a1_, rhs.a1_, 0&& ref_compare(a2_, rhs.a2_, 0);
    }

private:
    A1 a1_;
    A2 a2_;
}
;

对于bind(plus<int>(), _1, 1)来说,它返回了一个bind_t的对象,其中F的类型为plus<int>,f_的值为plus<int>(),
L的类型为list2<arg<1>,value<int> >,而l的a1_为_1,a2_为value<int>(1);
到这里,我们已经完整地看到bind所进行的一系列动作,根据传进来的占位符,推演到其类型,构造listX<A>,作为bind_t的第三个模板参数类型,bind_t的第二个模板参数F的类型也是确定的,这时候只有bind_t的第一个模板参数的类型R是未定的。

角色4:bind_t的调用

对于完整的bind的调用,上面的例子应该是如下:

bind(plus<int>(), _1, 1)(5);

注意到最后面的一对小括号,那是传递给匿名对象bind_t<R,plus<int>,list2<arg<1>,value<int> > >()的参数

由于返回的bind_t是临时对象,因此是const的,因此将调用的是const 的function call operator,请再回到前面“占位符”那里看一下bind_t的operator()定义,由于传递给bind_t的参数是5,因此被推演成int,因此最终将调用

template<class A1> result_type operator()(A1 & a1)
    
{
        list1
<A1 &> a(a1);
        
return l_(type<result_type>(), f_, a, 0);
    }

由以上调用可知,bind_t将operator()调用下发到list2<arg<1>,value<int> >的opeator(),接受的参数类型为
type<result_type>, plus<int>, list<int&>, int,其值分别为type<result_type>(), plus<int>(), list<int&>(5), 0

这时我们需要回顾前面给出的list2的operator(),注意到listN的operator()的最后一个参数是int,因此如果返回值类型是void的话,则会优先选择

template<class F, class A> void operator()(type<void>, F & f, A & a, int)
{
        unwrap(
&f, 0)(a[a1_], a[a2_]);
}


template
<class F, class A> void operator()(type<void>, F const & f, A & a, intconst
{
        unwrap(
&f, 0)(a[a1_], a[a2_]);
}

中的一个;否则将选择listN的其它operator()。

对于本例,R的类型没有 显示指定为void,因此选择其它operator(),在这里,将选择

template<class R, class F, class A> R operator()(type<R>, F & f, A & a, long)
 
{
      
return unwrap(&f, 0)(a[a1_], a[a2_]);
 }


即list2的operator()调用unwrap(&f,0)返回的函数指针,然后该函数根据传进来的实参a[a1_],a[a2_]进行调用。
由于a的类型是list1<int&>,根据其operator[],对于a1_,其类型为arg<1>,因此a[a1_]的值将是5,a2_的类型为value<int>,因此其值为1,到这里,已经把“占位符”的值全部替换为实参传递给函数进行调用。

角色5:unwrap

template<class F> inline F& unwrap(F * f, long)
{
    
return *f;
}


template
<class F> inline F & unwrap(reference_wrapper<F> * f, int)
{
    
return f->get();
}


template
<class F> inline F & unwrap(reference_wrapper<F> const * f, int)
{
    
return f->get();
}


template
<class R, class T> inline  dm<R, T> unwrap(R T::* * pm, int)
{
    
return  dm<R, T>(*pm);
}


template
<class R, class T> inline  dm<R, T> unwrap(R T::* const * pm, int)
{
    
return  dm<R, T>(*pm);
}

角色6: result_traits
bind_t的第一个模板参数R是返回值的类型,前面还没有涉及到R的推演过程,R都是一直做为参数一层一层往下
面传,当最终调用unwrap后,R的参数开始一层一层往上传,从而确定R的类型

template<class R, class F> struct result_traits
{
    typedef R type;
}
;

struct unspecified {};

template
<class F> struct result_traits<unspecified, F>
{
    typedef typename F::result_type type;
}
;

template
<class F> struct result_traits< unspecified, reference_wrapper<F> >
{
    typedef typename F::result_type type;
}
;

至此,bind的自上到下的整个调用过程已经完全呈现在我们面前,总结如下:
1.调用bind函数,将返回一个bind_t对象
2.传递实际的参数给bind_t,将调用bind_t的operator()
3.bind_t的operator()调用对应的listN的operator()
4.listN的operator调用unwrap,获得unwrap中的函数指针,函数指针以前面传递进来的实参进行调用
原创粉丝点击