Boost学习笔记之五 bind

 
Bind是boost中非常有用的一个组件,它比标准库中的bind1st和bind2nd更强大,更直观。好了现在开始剖析。
   int x = 1;
   int y = 2;
   boost::bind(fun,_1,_2)(x,y);
首先看看这段代码做了什么?boost::bind(f,_1,_2)返回一个函数对象。让我们来看看具体函数调用。(这里的bind实际上不是调用下面这个版本,这里为了讲解方便,先用这个版本)
template <class R, class F, class A1, class A2>
    _bi::bind_t<R, F, typename _bi::list_av_2<A1, A2>::type>
    bind(F f, A1 a1, A2 a2)
{
    typedef typename _bi::list_av_2<A1, A2>::type list_type;
    return _bi::bind_t<R, F, list_type> (f, list_type(a1, a2));
}
要明确bind针对不同的参数有不同的版本,这是两个参数的版本。看起来似乎很复杂。一点点的来剖析它吧。
首先看看它的返回类型_bi::bind_t<R, F, typename _bi::list_av_2<A1, A2>::type>
先把_bi::list_av_2<A1, A2>::type给干掉。
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;
};
这就是list_av2的定义。里面引入了一个add_value,来看看它是什么
template <class T> struct add_value
{
    typedef _bi::value<T> type;
};
它是一个极其简单的结构体,只做了一件事,定义了一个类型,里面用的了value,来看看它是什么。
template <class T> class value
{
public :
 
    value(T const & t): t_(t) {}
 
    T & get() { return t_; }
    T const & get() const { return t_; }
 
    bool operator==(value const & rhs) const
    {
        return t_ == rhs.t_;
    }
 
private :
 
    T t_;
};
很明显,它的主要工作就是申明一个T型的成员,那么就把最开始的那个函数定义打回原形。
template<class R, class F, class A1, class A2>
    _bi::bind_t<R, F, list2<value<A1>, value<A2> > >
    bind(F f, A1 a1, A2 a2)
{
       return _bi::bind_t<R, F, list2<value<A1>, value<A2>  > (f, list2<value<A1>, value<A2> >(a1, a2));
}
这里还涉及到list2这个类型。好的来看看它是什么。
template<class A1, class A2> class list2
{
public:
 
    list2(A1 a1, A2 a2): a1_(a1), a2_(a2) {}
 
    A1 operator[] (boost::arg<1>) const { return a1_; }
    A2 operator[] (boost::arg<2>) const { return a2_; }
 
 
    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 & a, long)
    {
        return unwrap(&f, 0)(a[a1_], a[a2_]);
    }
 
private:
 
    A1 a1_;
    A2 a2_;
};
可不要以为真实的list2只有这么几段代码,这里只是对它做了一个简化处理。为了方便抓住核心类容。先把几个关键结构看了,再来一起分析。来看看boost::arg<1>这一类的东西是什么。
template <int I> class arg
{
};
static boost::arg<1> _1;
static boost::arg<2> _2;
static boost::arg<3> _3;
static boost::arg<4> _4;
static boost::arg<5> _5;
static boost::arg<6> _6;
static boost::arg<7> _7;
static boost::arg<8> _8;
static boost::arg<9> _9;
对于不同的编译器是有一点区别的。但意思都是一样的。可以看见arg是一个空模板类。以后大显神通的_1,_2。。。就是这些类的对象。
再来看看关键的_bi::bind_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) {}
 
    template<class A1, class A2> R operator()(A1 & a1, A2 & a2)
    {
        list2<A1 &, A2 &> a(a1, a2);
        return l_(type<R>(), f_, a, 0);
    }
 
private:
 
    F f_;
    L l_;
 
};
当然这也是简化版本,真实的bind_t是很长的。好了再次拷贝上面的两段代码,来做整体分析了。
   int x = 1;
   int y = 2;
   boost::bind(fun,_1,_2)(x,y);
template<class R, class F, class A1, class A2>
    _bi::bind_t<R, F, list2<value<A1>, value<A2> > >
    bind(F f, A1 a1, A2 a2)
{
       return _bi::bind_t<R, F, list2<value<A1>, value<A2>  > (f, list2<value<A1>, value<A2> >(a1, a2));
}
这个函数返回一个_bi::bind_t对象,(忘了说了_bi是个命名空间)也就是说boost::bind(f,_1,_2)这里返回了一个对象。
return _bi::bind_t<R, F, list2<value<A1>, value<A2>  > (f, list2<value<A1>, value<A2> >(a1, a2));
看这一句做了什么,它调用bind_t的构造函数 bind_t(F f, L const & l): f_(f), l_(l) {}
做完这件事后bind_t的f为fun,l为list2<value<int>,value<int> >
那么当调用这个函数对象的operator()操作符的时候会发生什么事
    template<class A1, class A2> R operator()(A1 & a1, A2 & a2)
    {
        list2<A1 &, A2 &> a(a1, a2);
        return l_(type<R>(), f_, a, 0);
    }
比如说这里boost::bind(fun,_1,_2)(x,y);
发生的事就是定义一个list2<int,int>a(x,y);然后调用l_(type<R>(), f_, a, 0);也就是
List2<value<int>,value<int> >(type<R>(),f_,a,0);
这里template<class T> class type {};也是一个空模板类。
在这里调用l_的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_]);
    }
先来看看这里的a,它也是个list2对象。好了来看看a[a1_]这里,
A1 operator[] (boost::arg<1>) const { return a1_; } ,这里重载了operator[]操作符。首先要分清楚return unwrap(&f, 0)(a[a1_], a[a2_]);这里里面的al可不是
A1 operator[] (boost::arg<1>) const { return a1_; } 这里的al,一旦高混就麻烦了,会看半天,越看越晕。return unwrap(&f, 0)(a[a1_], a[a2_]);在这里而言这个al_是bind_t中的l_的,它的是_1,它的类型是boost::arg<1>,这样a[a1_],才可以求出a中的第一个参数,针对这里的x。
unwrap(&f, 0) 就是返回函数指针。
让后这一切就相当于fun(x,y)了。
事情还没有完,为什么没有些R,却可以推导出R来,看看真实的世界
template <class R, class B1, class B2, class A1, class A2>
    _bi::bind_t<R, bind_ST R (bind_CC *) (B1, B2), typename _bi::list_av_2<A1, A2>::type>
    bind(bind_ST R (bind_CC *f) (B1, B2), A1 a1, A2 a2)
{
    typedef bind_ST R (bind_CC *F) (B1, B2);
    typedef typename _bi::list_av_2<A1, A2>::type list_type;
    return _bi::bind_t<R, F, list_type> (f, list_type(a1, a2));
}
这里是可以通过函数指针推导出R来的,看看上面没有讲完的部分。type<R>,是个空模板类,似乎没有起到作用,但它是有用的,只有bind_t类型才知道R的确切类型。
return l_(type<R>(), f_, a, 0); 它的作用就是讲R类型传递给l_,
template<class R, class F, class A> R operator()(type<R>, F & f, A & a, long)
这样在list2中就可以使用R类型了。
最后bind一共有十个重载版本,可以0-9个参数,所以它是远强大于bind1st和bind2nd的。其他几个重载版本原理是一样的。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值