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个参数*/);

完结,但愿对你们有帮助。

相关文章
相关标签/搜索