boost bind初步探究 (一)

2014-11-24 00:59:37 · 作者: · 浏览: 13

最近对boost的bind部分比较感兴趣,对其背后的机制进行了简单的分析,和大家分享一下。


注,我所看的代码是boost_1_51_0, 想来各个版本的差异不大。

从一个例子开始
直接上代码(从官方网站摘取)


定义函数


[cpp]
int f(int a, int b)
{
return a + b;
}

int g(int a, int b, int c)
{
return a + b + c;
}

int f(int a, int b)
{
return a + b;
}

int g(int a, int b, int c)
{
return a + b + c;
}调用范例:


bind(f, 1, 2)(); //f(1,2)

bind(f, _2, _1)(x, y); // f(y, x)

bind(g, _1, 9, _1)(x); // g(x, 9, x)

bind(g, _3, _3, _3)(x, y, z); // g(z, z, z)

bind(g, _1, _1, _1)(x, y, z); // g(x, x, x)


_1, _2, ... _9在 boost中被称为placeholder,是占位符的意思。它表示参数。这种方式,我是只在boost中见过,是个非常神奇的用法。

它们究竟是什么呢?,且看定义:(boost/bind/placeholders.hpp)


[cpp]
boost::arg<1> _1;
boost::arg<2> _2;
boost::arg<3> _3;
boost::arg<4> _4;
boost::arg<5> _5;
boost::arg<6> _6;
boost::arg<7> _7;
boost::arg<8> _8;
boost::arg<9> _9;

boost::arg<1> _1;
boost::arg<2> _2;
boost::arg<3> _3;
boost::arg<4> _4;
boost::arg<5> _5;
boost::arg<6> _6;
boost::arg<7> _7;
boost::arg<8> _8;
boost::arg<9> _9;
boost::arg也是个模板,至于是什么样的模板,留个悬念吧。

boost bind的这些功能,颠覆了我对C++的看法,从未想到过,C++还可以这么玩。那么,boost究竟是怎么实现的呢?


读者请注意,bind在这里涉及了两个参数表。第一个参数表是被bind绑定的函数(例子中f,g函数)的参数表,另外一个是bind生成的新的函数对象的参数表。

这两个参数表如何实现?如何转换是我们后面分析的重点。

bind是什么?
bind是函数,是非常神奇的函数,不是一个函数,而是一组函数,是一组重载的函数。

翻开代码 boost/bind/bind.hpp,找到BOOST_BIND字符串,大约在1290行的位置,boost定义了bind(1.51.0):


[cpp]
// bind

#ifndef BOOST_BIND
#define BOOST_BIND bind
#endif

// generic function objects

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

template
_bi::bind_t::type>
BOOST_BIND(F f, A1 a1)
{
typedef typename _bi::list_av_1::type list_type;
return _bi::bind_t (f, list_type(a1));
}


template
_bi::bind_t::type>
BOOST_BIND(F f, A1 a1, A2 a2)
{
typedef typename _bi::list_av_2::type list_type;
return _bi::bind_t (f, list_type(a1, a2));
}
....

// bind

#ifndef BOOST_BIND
#define BOOST_BIND bind
#endif

// generic function objects

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

template
_bi::bind_t::type>
BOOST_BIND(F f, A1 a1)
{
typedef typename _bi::list_av_1::type list_type;
return _bi::bind_t (f, list_type(a1));
}


template
_bi::bind_t::type>
BOOST_BIND(F f, A1 a1, A2 a2)
{
typedef typename _bi::list_av_2::type list_type;
return _bi::bind_t (f, list_type(a1, a2));
}
....
太多了,只贴3个,足以说明问题。

模板参数


R 表示返回类型
F 表示函数指针的类型
A1,A2, .... 这些都是参数的类型
boost将BOOST_BIND定义为bind。所以,你看到的BOOST_BIND就是对bind函数的定义。


bind函数非常简单,它其实就是返回一个bind_t类的对象。bind_t类也是一个模板类。 如果仔细观察,你可以发现,这些不同参数的bind函数,其实现上不同在于list_av_N这一系列的辅助类是不同的。list_av_1表示一个参数,list_av_2表示两个参数, 以此类推。


这里的list_av_N对象,是第一个参数表,是函数F要求的参数表,这个参数表是可以包含placeholder的。


list_av_N对象其实只是一个包装对象。我们以list_av_2为例:
[cpp]
template struct list_av_2
{
typedef typename add_value::type B1;
typedef typename add_value::type B2;
typedef list2 type;
};

template struct list_av_2
{
typedef typename add_value::type B1;
typedef typename add_value::type B2;
typedef list2 type;
};
list_av_2的作用,仅仅是为了包装而已。list_av_2::type == ist2 == list_type。


bind_t是什么东东
奥秘在bind_t中,且看bind_t的定义 (也在boost/bind/bind.hpp中。下面只是bind_t的一种定义方法,但是道理都是一样的)
[html]

template class bind_t
{
public:

typedef bind_t this_type;

bind_t(