西城

指尖代码,手上年华

联系 聚合 管理
  20 Posts :: 0 Stories :: 62 Comments :: 0 Trackbacks
bind实质上是一个函数。
#ifndef BOOST_BIND
#define BOOST_BIND bind
#endif
在此文件内将其定义为BOOST_BIND.以下均以BOOST_BIND代指bind.

 

template<class R, class F>
    _bi::bind_t<R, F, _bi::list0>
    BOOST_BIND(F f)
{
 typedef _bi::list0 list_type;
 return _bi::bind_t<R, F, list_type> (f, list_type());
}

 

此函数的返回值是_bi::bind_t<R,F,_bi::list0>,参数是F,这是针对无参函数的版本。
_bi是文件中定义于boost命名空间之下的一个命名空间,bind实现的细节均在其中(bind implementation).
下面看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) {}

#define BOOST_BIND_RETURN return
#include <boost/bind/bind_template.hpp>
#undef BOOST_BIND_RETURN
};

 

看起来很小,只有一个类型定义和一个构造函数。但注意include那一句,这意味着整个bind_template.hpp文件都
是bind_t类的一部分。而bind_tmplate文件差不多有350行。因为函数体都很小,所以直接在类内定义,成为inline.所以,当要定义的一个类特别大时,将其具体的函数
实现放置于另一个文件中也是一个很好的办法。
下面来看bind_template.hpp中属于_bi::bind_t的一些成员定义。

typedef typename result_traits<R, F>::type result_type; result_traits
提取返回值。在bind.hpp中将其定义为R。

    result_type operator()()
    {
        list0 a;
        BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
    }
后面依次是operator()的const版本,一直到九个参数的版本。BOOST_BIND_RETURN可以直接当作return.
list0类也有九个。


看一个例子
int f()
{
    return 1;
}
bind(f)()应该等于f().
bind函数中返回值是:
_bi::bind_t<R, F, list_type> (f, list_type());list_type=_bi::list0。所以返回值是一个特化的模板类。
f的类型为int (*)(),即是F。所以返回值是
_bi::bind_t<intint(*)(),_bi::list0>(f,_bi::list0());

 R为萃取出的返回值(int)。通过此构造函数,构造出了一个bind_t类,f,list0,分别由bind_t的相应私有数据存储起来。
然后是调用此类(函数体).即bind(f)(),bind_t重载了相应的()运算符。
还是依参数个数不同有不同的表现形式,此例没有参数,其表现形式为:

    result_type operator()() 
    {
        list0 a;
        BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
    }
返回值即为原来的int.函数实现这一块交给list0(l_).list0(type<int>(),f,a,0).
type<int>()生成了一个空的类。l_已经是一个生成的类,所以此处调用的是重载操作符().
    template<class R, class F, class A> R operator()(type<R>, F & f, A &, long)
    {
        return unwrapper<F>::unwrap(f, 0)();
    }

又调用unwrapper结构体。因为是static,所以不用再生成类的实例,最后返回的就是原来的那个f()------->int。
template<class F> struct unwrapper
{
    static inline F & unwrap( F & f, long )
    {
        return f;
    }

    template<class F2> static inline F2 & unwrap( reference_wrapper<F2> rf, int )
    {
        return rf.get();
    }

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

其他参数不同的情况与此类似。bind对不同数目的参数都有相应一致的处理方式。但是依据相应类的个数以及bind的重载个数,参数值最多只能有9个。这样限制一般也
没什么大的影响,因为一般的参数个数没有这么多。如果用的参数有太多的话,其实可以在源码上再加上一种重载形式即可。

上面的实现绕了这么大的一圈,其实最后调用的还是原来的那个函数,看似费时,其实都是为了泛型的必要。bind能够绑定的函数类型大大地增加,不管是普通的函数
指针,还是函数体,以及没有result_type的类型,bind都可以很好的运作。而且还可以与ref库结合起来使用。

在C++的这些第三方库里面,BOOST是比较特别的一个。因为它并不是专注于一个问题,而是涉及到了语言的各个层面。有很多接近于语言底层的特性,所以BOOST库比
任何一个库都更值得我们去研究,揣摩。

 

posted on 2012-04-02 11:38 西城 阅读(2636) 评论(2)  编辑 收藏 引用 所属分类: C/C++Boost

Feedback

# re: Boost::bind源码分析:bind.hpp 2012-04-03 19:47 空明流转
其实很多东西揣摩了没啥用处。
有些就是语言机制的缺陷。
比方说static assert,比方说这么多转发。
Varidic Template和Perfect Forward一出来了,很多tricky都失效了。。。  回复  更多评论
  

# re: Boost::bind源码分析:bind.hpp 2012-04-03 22:25 墨魂
@空明流转
这样至少用的时候知道是怎么回事。又有那个语言是完美的呢?都是人设计的,都会有缺陷。自己尽为吧。  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理