5.6.11

How does boost::bind work?

If you are not already familiar with Boost::bind you may want to explore: http://www.boost.org/doc/libs/1_44_0/libs/bind/bind.html

To understand how bind works, I would write a simple example binder first and then start digging into boost::bind.

struct placeholder{};
placeholder _1;

template
struct mybinder_t
{
A ma;
T* mt;
R (T::*fn) (A);
R operator() ( )
{
return (mt->*fn)(ma);
}
};

template
mybinder_t mybind(R (T::*f)(A), T* t, A a, placeholder p)
{
mybinder_t tmp;
tmp.fn = f;
tmp.ma = a;
tmp.mt = t;

return tmp;
}


class IsItEvenObj
{
public:
bool is_even(int i)
{
return (i%2 == 0);
}
};

int main()
{
IsItEvenObj obj;
  mybinder_t<bool, IsItEvenObj, int> is_5_even = mybind(&IsItEvenObj::is_even, &obj, 5, _1);

cout << boolalpha ; cout << is_5_even() << endl; } 


When you used bind the first time,  you might have wondered what _1, _2 etc meant. These are placeholder variables of type boost::arg. So, you can declare variables with different names if you want. Boost bind uses placeholders as declare in /usr/include/boost/bind/placeholders.hpp. 


They are declared as follows: 

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;
There are 9 placeholders because bind supports upto 9 parameters to be bound. But what do these placeholders do? Let's dig into what boost::arg does. 

It is defined in /usr/include/boost/bind/arg.hpp It looks like: 

template< int I > struct arg
{     
arg()     {     }     
template< class T > arg( T const & /* t */ )     
 {
        // static assert I == is_placeholder<T>::value         
        typedef char T_must_be_placeholder[ I == is_placeholder<T>::value? 1: -1 ];
  } 
}; 


To be honest there is nothing much in there. And that is the fact, placeholders are only dummy variables. They are only there to help bind pick up the right overload. (I will explain what this means below) Having actually told what placeholders are, let's look into bind itself.

Let's go into /usr/include/boost/bind/bind.hpp. 

The first thing to note is:

// bind
#ifndef BOOST_BIND
#define BOOST_BIND bind
#endif 

So, bind is BOOST_BIND in here. Now let's look at the bind function itself. This is how boost::bind actually looks:
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, list_type> (f, list_type(a1, a2));
}

So on upto 9 overloads:

template<class R, class F, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
    _bi::bind_t<R, F, typename _bi::list_av_9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::type>
    BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9)
{
    typedef typename _bi::list_av_9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::type list_type;
    return _bi::bind_t<R, F, list_type>(f, list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9));
}

1 comment:

  1. Boost 1.44 online browsable boost::bind LXR source code: http://alxr.usatlas.bnl.gov/lxr/source/external/Boost_1.44.0_python2.6/boost-1_44/boost/bind/

    ReplyDelete