
Hi Arkadiy,
"Fernando Cacciola" <fernando_cacciola@hotmail.com> 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; } **********************