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<int, int(*)(),_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库比
任何一个库都更值得我们去研究,揣摩。