Boost logo

Boost :

From: Fernando Cacciola (fernando_cacciola_at_[hidden])
Date: 2006-11-03 12:27:54


Hi Arkadiy,

> "Fernando Cacciola" <fernando_cacciola_at_[hidden]> wrote
>
>> Say I have a few arbitraty function objects:
>>
>> A a ; B b ; C c ;
>>
>> I can easily pipe them toghether using Boost.Bind:
>>
>> bind(a, bind(b, bind(c,_1) ) )(some_starting_value);
>>
>> But how do I create such a composed functor programatically from an
>> aribtrary tuple of function objects, as in tuple<A,B,C>?
>>
>> The idea is to present to the user a simple interface were he pass
>> just a tuple of functors and I do the magic of turning them into a
>> pipe.
>
> I think you may need Fusion to do this...

I forgot to mention a small detail: I can only use tuple/bind and hand-made
metaprogramming because this is to be integrated into a framework that
requires at most Boost 1.32.0. Small detail ;)

Anyway, I almost got it (following basically the same idea you've posted),
until I hit a show stopper:

A bind expression returns an object of type _bi::bind_t<>
But as it turns out, such objects are not copy constructible, so I can't do
something like this:

a_bind_object fwd_to_bind(a,b) { return bind(a,b) ; }

IOW, it appears that a bind expression isn't a first-class high order
function.

Or else I'm missing something...

FWIW here's what I got so far:
It doesn't compile becuase of the missing copy constructor in bind_t

************
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>

using namespace std ;
using namespace boost ;

//
// A,B,C are just sample unary functors
//
struct A
{
  typedef int result_type ;
  template<class T>
  int operator() ( T v ) const { return static_cast<int>(v * 2) ; }
} ;

struct B
{
  typedef double result_type ;
  template<class T>
  double operator() ( T v ) const { return static_cast<double>(v / 3) ; }
} ;

struct C
{
  typedef string result_type ;
  template<class T>
  string operator() ( T v ) const { return "hello" ; }
} ;

template<class Functors, int N> struct get_bind_expr_type ;

template<class Functors, int N>
struct get_bind_argument_type
{
 typedef typename get_bind_expr_type<Functors,N-1>::type type ;
} ;

template<class Functors>
struct get_bind_argument_type<Functors,0> { typedef boost::arg<0> type ; } ;

//
// hand-made equivalent of a recursive
typeof(bind(f[0],bind(f[1],bind(f[2],_1)))
//
template<class Functors, int N>
struct get_bind_expr_type
{
  typedef typename ::boost::tuples::element<N,Functors>::type Functor ;

  typedef typename Functor::result_type functor_result_type ;

  // This should be the result type of the previous functor in real code
  typedef typename Functor::result_type functor_argument_type ;

  // NOTE: the recursion is inside this metafucntion
  typedef typename get_bind_argument_type<Functors,N>::type
bind_argument_type ;

  typedef _bi::bind_t<functor_result_type
                     ,functor_result_type (*) ( functor_argument_type )
                     ,typename _bi::list_av_1<bind_argument_type>::type
>
                     type ;
} ;

template<class Functors, int N>
struct functor_pipe_impl
{
  typedef typename get_bind_expr_type<Functors,N>::type result_type ;

  static result_type apply( Functors const& functors )
  {
    return bind(functors.get<N>(),
functor_pipe_impl<Functors,N-1>::apply(functors) );
  }
} ;

template<class Functors>
struct functor_pipe_impl<Functors,0>
{
  static boost::arg<1> apply( Functors const& functors ) { return
boost::arg<1>() ; }
} ;

//
// Recursively creates and returns a bind expression of the form:
//
// bind(Functors[0],bind(Functors[1],...,bind(Functors[N-1],_1)))
//
template<class Functors>
typename get_bind_expr_type< Functors,
::boost::tuples::length<Functors>::value - 1>::type
make_functor_pipe( Functors const& functors )
{
  return functor_pipe_impl<Functors,
::boost::tuples::length<Functors>::value - 1 >::apply(functors);
}

//
// Sample usage code
//
template<class T,class Pipe>
void bar ( T const& v, Pipe const& pipe )
{
 cout << "calling pipe: " << pipe(v) << endl ;
}

template<class T,class Functors>
void foo ( T const& v, Functors const& policies )
{
  bar(v,make_functor_pipe(policies));
}

int main(int argc, char* argv[])
{
 A a ; B b ; C c ;

 foo(3,make_tuple(a,b,c));

 return 0;
}
**********************


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk