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手法,即
回到正题,首先给出bind各种“占位符”的实现:
有了以上用于bind的“占位符”,我们接着看这些“占位符”是怎么被实际的参数所取代的。
角色2. bind如何构造bind_t对象,仍以接受两个占位符的bind为例
即将传递进来的占位符类型通过捆绑成一个更大的类型list_av_X,具体定义如下
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
对于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_t<R,plus<int>,list2<arg<1>,value<int> > >()的参数
由于返回的bind_t是临时对象,因此是const的,因此将调用的是const 的function call operator,请再回到前面“占位符”那里看一下bind_t的operator()定义,由于传递给bind_t的参数是5,因此被推演成int,因此最终将调用
由以上调用可知,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的话,则会优先选择
中的一个;否则将选择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
角色6: result_traits
bind_t的第一个模板参数R是返回值的类型,前面还没有涉及到R的推演过程,R都是一直做为参数一层一层往下
面传,当最终调用unwrap后,R的参数开始一层一层往上传,从而确定R的类型
至此,bind的自上到下的整个调用过程已经完全呈现在我们面前,总结如下:
1.调用bind函数,将返回一个bind_t对象
2.传递实际的参数给bind_t,将调用bind_t的operator()
3.bind_t的operator()调用对应的listN的operator()
4.listN的operator调用unwrap,获得unwrap中的函数指针,函数指针以前面传递进来的实参进行调用
引用《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
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_;
};
{
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));
}
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));
}
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;
};
{
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, long) const
{
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, int) const
{
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_;
};
{
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, long) const
{
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, int) const
{
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);
}
{
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, int) const
{
unwrap(&f, 0)(a[a1_], a[a2_]);
}
{
unwrap(&f, 0)(a[a1_], a[a2_]);
}
template<class F, class A> void operator()(type<void>, F const & f, A & a, int) const
{
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);
}
{
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;
};
{
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中的函数指针,函数指针以前面传递进来的实参进行调用
- boost之bind源码剖析
- boost源码剖析之any
- boost源码剖析之:boost::multi_array
- boost源码剖析之:boost::multi_array
- boost源码剖析之:boost::multi_array
- Boost源码剖析之:容器赋值-assign
- Boost源码剖析之:容器赋值-assign
- boost源码剖析之:Tuple Types
- Boost源码剖析之:容器赋值-assign
- std::bind源码剖析
- 【boost学习】之boost::bind
- boost学习之bind
- 2.Boost之bind
- Boost库之bind
- 《boost源码剖析》系列
- boost源码剖析
- boost.function源码剖析
- Boost源码剖析开篇
- JavaBean简介
- 转载课程英文名称
- 写程序
- 类的调用问题
- ELF文件的动态链接器 原理 设计和代码 - ChinaUnix.net
- boost之bind源码剖析
- 新手学堂:应用程序在Linux上的执行过程 — IT技术 - 赛迪网
- 关于jsp中存取图片的问题
- IT十余年心得
- RegExp函数的含义
- 推荐最好的程序员专用字体proggy
- 动态规划总结《一》pku 2533 longest odered subsequence
- 优秀网站源码、编程源码下载网站
- 类文件具有错误的版本 50.0,应为 49.0