Without spending a long time reviewing the boost source code, could someone give me a quick rundown of how boost bind is implemented?
I think it's a template class that declares a member variable for the arguments you want to bind and overloads () for the rest of the arguments.
Bind has some very complex internal machinery and I don't really understand it myself. Probably the best way to get a hold of the workings would be to email the authors (a quick skim of the documentation doesn't seem to provide any addresses). There are a number of other issues that make it more complex, such as the fact that bind<R>()
doesn't do checking like bind()
does and compiler coughBorlandcough workarounds.
I like this piece of the bind
source:
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
};
Tells you almost all you need to know, really.
The bind_template
header expands to a list of inline operator()
definitions. For example, the simplest:
result_type operator()()
{
list0 a;
BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
}
We can see the BOOST_BIND_RETURN
macro expands to return
at this point so the line is more like return l_(type...)
.
The one parameter version is here:
template<class A1> result_type operator()(A1 & a1)
{
list1<A1 &> a(a1);
BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
}
It's pretty similar.
The listN
classes are wrappers for the parameter lists. There is a lot of deep magic going on here that I don't really understand too much though. They have also overloaded operator()
that calls the mysterious unwrap
function. Ignoring some compiler specific overloads, it doesn't do a lot:
// 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();
}
The naming convention seems to be: F
is the type of the function parameter to bind
. R
is the return type. L
tends to be a list of parameter types. There are also a lot of complications because there are no less than nine overloads for different numbers of parameters. Best not to dwell on that too much.
By the way, if bind_t
is collapsed and simplified by including boost/bind/bind_template.hpp
, it becomes easier to understand like the following :
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;
...
template<class A1>
result_type operator()(A1 & a1)
{
list1<A1 &> a(a1);
return l_(type<result_type>(), f_, a, 0);
}
private:
F f_;
L l_;
};