最近对boost的bind部分比较感兴趣,对其背后的机制进行了简单的分析,和大家分享一下。
注,我所看的代码是boost_1_51_0, 想来各个版本的差异不大。
从一个例子开始
直接上代码(从官方网站摘取)
定义函数
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)
它们究竟是什么呢?,且看定义:(boost/bind/placeholders.hpp)
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):
// bind
#ifndef BOOST_BIND
#define BOOST_BIND bind
#endif
// generic function objects
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());
}
template<class R, class F, class A1>
_bi::bind_t<R, F, typename _bi::list_av_1<A1>::type>
BOOST_BIND(F f, A1 a1)
{
typedef typename _bi::list_av_1<A1>::type list_type;
return _bi::bind_t<R, F, list_type> (f, list_type(a1));
}
template<class R, class F, class A1, class A2>
_bi::bind_t<R, F, typename _bi::list_av_2<A1, A2>::type>
BOOST_BIND(F f, A1 a1, A2 a2)
{
typedef typename _bi::list_av_2<A1, A2>::type list_type;
return _bi::bind_t<R, F, l