Pages

About Me - 关于我

My photo
Madison, WI, United States
Joy Young ~~

2012/07/21

My version of boost.bind using C++ 11

One day I discussed with a C++ guru how to implement boost.bind (or C++ functional.bind). Here I posts some idea in doing it. It implements bind_3. It uses C++11 features: variadic template and tuple to simplify the complicated method used in boost library.
#include <tuple>
#include <type_traits>
#include <iostream>
using namespace std;
 template<int i> //use int to identify which placeholder I am using.
struct PH
{
 };
//Dectect if it is a placeholder and if the answer is yes, tell me which (value) I am using.
template<typename _Tp>
struct is_placeholder : public integral_constant<int, 0>
{ };
template<int i>
struct is_placeholder<PH<i>>  : public integral_constant<int, i>
{ };
 //ArgMap is the "mapping rule" of the arguments.
//It takes a value of type T, and returns this value if T is not a placeholder;
// otherwise it returns the argument at the corresponding position in the argument list.
template<int idx, class T, class ... Args>
struct ArgMap{
      static auto arg_at(T val, tuple<Args...>  arg_list) -> decltype(get<idx - 1>(arg_list))
      {
          return get<idx-1>(arg_list); //idx indicating which argument I should retrieve. e.g. idx = 2, means it should return the 2nd argument of arg_list
      }
 };
template<class T, class ... Args>
struct ArgMap<0, T, Args...>{ //0 indicating not a placeholder
      static T arg_at(T val, tuple<Args...>  arg_list)
      {
          return val;
      }
 };
template<class R,class F, class T1,class T2,class T3>
struct my_bind_3{
      T1 _t1;
      T2 _t2;
      T3 _t3;
      F   _pf;
      my_bind_3(F pf,T1 t1, T2 t2, T3 t3)
          : _pf(pf),
            _t1(t1),
            _t2(t2),
            _t3(t3)
      {}
      //the code above of this class are all yours, I only chaneged the operator();
      template<class ...ArgList>
      R operator()(ArgList ... args)
      {
         tuple<ArgList...> arg_list (args...); //We need to store the argument list.
   
         //In plainer words, it is doing: return  F(arg_list [bind_list[0]],arg_list [bind_list[1]], arg_list [bind_list[2]], …… );
         //note that,  _t1, _t2, _t3 are, as a matter of fact now, bind_list[0], bind_list[1], bind_list[2];
          return (*_pf)( ArgMap<is_placeholder<T1>::value, T1, ArgList... >::arg_at(_t1, arg_list),
                     ArgMap<is_placeholder<T2>::value, T2, ArgList...  >::arg_at(_t2, arg_list),
                     ArgMap<is_placeholder<T3>::value, T3, ArgList...  >::arg_at(_t3, arg_list));
      }
};

 template<class R, class F, class T1,class T2,class T3>
my_bind_3<R,F,T1,T2,T3> bind_3(F fn, T1 arg1, T2 arg2, T3 arg3 )
{
      return my_bind_3<R,F,T1,T2,T3>(fn, arg1, arg2, arg3);
}
 void show(int i, int j, int k)
{
     cout<<i<<j<<k<<endl;
 }
PH<1> _1;
PH<2> _2;
 int main()
{
     bind_3<void>(show, 5, _1, _2)(6, 7);
     bind_3<void>(show, 5, _2, _1)(6, 7);
     bind_3<void>(show, 2, 3, 4)();

 }
//output:
//567
//576
//534

No comments:

Post a Comment