boost::bind和占位符实现的原理(from AV BOOST)

来源:互联网 发布:淘宝贴片图 编辑:程序博客网 时间:2024/06/06 07:52

boost.bind是个非常强大的工具,有了它,我们可以轻松的将不同模块的代码,从物理上分离,从而达到解耦的作用。

当你开始尝试使用boost.bind来进行编程的时候,你会发现自己不知不觉中贱贱的爱上了boost.bind,因为作用不止是解耦,还有很多说不尽道不明的地方需要它。

但是从来很少有人详细的说明它是如何工作(实现)的,这里,我打算用一小段简单的代码,模拟boost.bind以及占位符的实现,以达到阐述boost.bind原理,希望能对你有所帮助。

实现例子:

#include <string>
#include <boost/function.hpp>
namespace
{
class placeholder_ {};
placeholder_ __1; // 以双下划线开头的占位符__1,双下划线区别下boost.bind里的_1。
}


// 一个接受单个参数的用于bind类的成员函数模板实现,实例化后的对象,实际上就是一个函数对象。
// 这个函数对象的调用没有参数(即operator()),因为参数在构造时传入,并保存在成员Arg& a_中,
// 这样,在调用这个函数对象时,就不再需要传入参数了。
template <typename R, typename T, typename Arg>
class simple_bind_t
{
private:
typedef R (T::*F)(Arg);
F f_;
T* t_;
Arg& a_;


public:
// 构造函数,确定了F,T,Arg,分别是成员函数指针,类对象指针,实际传入的参数。
// 比如在: simple_bind(&bind_test::print_string, &t, h)(); 中,第一个就是类的成员函数地址。
// 第二个就是指向对象的地址,第三个就是实际调用的参数h。
simple_bind_t(F f, T* t, Arg &a)
: f_(f), t_(t), a_(a)
{}


R operator()() // 无参数,参数在bind时确实,并保存在a_,调用时就不需要传入参数了。
{
return (t_->*f_)(a_);
}
};


// 这个类基本同上,也是一个接受单个参数的用于bind类的成员函数模板实现,唯一不同的是
// 它主要是为了使用占位符,所以,它的构造函数参数没有了Arg,Arg是在这个函数对象真正
// 被调用时,由用户传入。
template <typename R, typename T, typename Arg>
class simple_bind_t2
{
private:
typedef R (T::*F)(Arg);
F f_;
T* t_;


public:
simple_bind_t2(F f, T* t)
: f_(f), t_(t)
{}


R operator()(Arg& a) // 有参数! 调用时由用户传入!
{
return (t_->*f_)(a);
}
};


// 下面是各种simple_bind的重载,这样就可以在用户使用的时候,传入不同的参数,自动
// 匹配到相应的simple_bind函数。


// 第一个simple_bind函数实现,调用参数由用户传入,并保存到simple_bind_t的成员a_里面。
// 这个函数返回simple_bind_t实例化后的函数对象,调用这个函数对象时无需传入参数。
template <typename R, typename T, typename Arg>
simple_bind_t<R, T, Arg> simple_bind(R (T::*f)(Arg), T* t, Arg& a)
{
return simple_bind_t<R, T, Arg>(f, t, a);
}


// 第二个simple_bind函数实现,可以看到占位符对象实际上是被丢弃掉
// 的,调用参数在实际调用时传入。
template <typename R, typename T, typename Arg>
simple_bind_t2<R, T, Arg> simple_bind(R (T::*f)(Arg), T* t, placeholder_& a)
{
return simple_bind_t2<R, T, Arg>(f, t);
}




// 一个用于我们自己实现的simple_bind的类。
class bind_test
{
public:
void print_string(const std::string str)
{
printf("%s", str.c_str());
}
};


// 下面是测试代码。
void test()
{
bind_test t;
std::string h = "hehe\n";


// 不使用占位符,直接在bind时传入,调用时不需要参数。
simple_bind(&bind_test::print_string, &t, h)();


// 使用占位符,参数在调用时传入。
simple_bind(&bind_test::print_string, &t, __1)(h);


// 还可以使用boost.function保存我们自己实现的simple_bind绑定后的结果,和
// 使用boost.function保存boost.bind完全兼容。
// 由此,大家可以想象一下boost.function的实现原理。
boost::function<void (const std::string)> f;
f = simple_bind(&bind_test::print_string, &t, __1);
f(h);
}


结论:

bind返回的结果实际是一个函数对象(注意:和boost.function没有关系,有人认为bind返回的是boost.function,这是错误的!bind返回的东西和boost.function没有关联。),参数和函数指针被保存在这个函数对象里面,在函数对象的operator()中实际调用。

OK,到这里为止,如果你仔细阅读了上面的代码以及注解,并理解了bind的话,请点击赞表示支持!谢谢!
如果有什么不明白,欢迎回复讨论。


0 0