How does boost bind work behind the scenes in general?
-
02-07-2019 - |
Question
Without spending a long time reviewing the boost source code, could someone give me a quick rundown of how boost bind is implemented?
Solution
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.
OTHER TIPS
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_;
};
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.