|
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