programmatically building a bind composition?

Hi people 3 years of C# programming is eroding my metaprogramming habilities :( 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. TIA -- Fernando Cacciola SciSoft http://fcacciola.50webs.com/

"Fernando Cacciola" <fernando_cacciola@hotmail.com> wrote
I think you may need Fusion to do this... The pseudocode would be roughly something like: unspecified compose(Tuple t, F f) { return compose(tail(t), bind(head(t), f)), } F compose(EmptyTuple, F f) { return f; } compose(tuple(a, b, c), _1) (except I think the order may be inverted) But I don't think current boost::tuple allows for extracting head and tail. Fusion may also have some kind of "fold" algorithm to do this, but I am not sure. Also, if you can't use typeof, you would have to get into bind's implementation details to calculate the return type. FWIW. Regards, Arkadiy

Hi Arkadiy,
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; } **********************

Hi Peter,
Oops, of course. But even fixing that I still get the same error: Error 1 error C2664: 'boost::_bi::bind_t<R,F,L>::bind_t(const boost::_bi::bind_t<R,F,L> &)' : cannot convert parameter 1 from 'boost::_bi::bind_t<R,F,L>' to 'const boost::_bi::bind_t<R,F,L> &' d:\programacion\projects\policypipe\policypipe\policypipe.cpp 120 Here: static result_type apply( Functors const& functors ) { ========> return bind(functors.get<N>(), functor_pipe_impl<Functors,N-1>::apply(functors) ); } The compiler, VC8.0, is refusing to copy construct the bind_t object. Any idea why? FWIW I tried the same with LL::bind and I get the same kind of error (can't copy construct functor_base<...>) TIA Fernando Cacciola

Fernando Cacciola wrote:
Besides the error, that's the general way to go? (when I can only use tuple/bind of course)
Defining the function object directly without going through bind, as suggested by Bryan Ewbank, may be easier. The pseudocode is trivial: struct pipe { tuple tp; operator()( A1 & a1 ) { return tp[0]( pipe( tp[rest] )( a1 ) ); } }; but the actual implementation may be hard. :-)

----- Mensaje original ----- De: Peter Dimov <pdimov@mmltd.net> Fecha: Viernes, Noviembre 3, 2006 9:48 pm Asunto: Re: [boost] programmatically building a bind composition? Para: boost@lists.boost.org
I think the following should do, but I don't have here a powerful enough compiler (i.e. supporting boost::result_of) to try: #include <boost/tuple/tuple.hpp> #include <boost/utility/result_of.hpp> template<typename Const> struct cons_bind; template<typename F,typename G> struct cons_bind<boost::tuples::cons<F,G> > { typedef boost::tuples::cons<F,G> cons; typedef cons_bind<G> next; template<typename Arg> struct result:boost::result_of< F(typename next::template result<Arg>::type)
{}; template<typename Arg> static typename result<Arg>::type call(const cons& c,const Arg& a) { return c.head(next::call(c.tail,a)); } }; template<typename F> struct cons_bind<boost::tuples::cons<F,boost::tuples::null_type> > { typedef boost::tuples::cons<F,boost::tuples::null_type> cons; template<typename Arg> struct result:boost::result_of<F(Arg)> {}; template<typename Arg> static typename result<Arg>::type call(const cons& c,const Arg& a) { return c.head(a); } }; template<typename Tuple> struct tuple_bind { tuple_bind(const Tuple& t):t(t){} typedef cons_bind<typename Tuple::inherited> helper_cons_bind; template<typename Arg> typename helper_cons_bind::template result<Arg>::type operator()(const Arg& a) { return helper_cons_bind::call(t,a); } private: Tuple t; }; // testing #include <cmath> #include <iostream> int main() { typedef boost::tuple< double (*)(double), double (*)(double)
tuple_t;
tuple_t t(std::sin,std::cos); tuple_bind<tuple_t> tb(t); std::cout<<tb(0.0)<<std::endl; }; HTH Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

Perhaps I'm misunderstanding or oversimplifying, but doesn't this work? template<class A, class B, class C> class Pipeline { public: Pipeline(A & a, B & b, C & c) : a_(a), b_(b), c_(c) { } public: template<class ARG> void operator()(ARG starting_val) { c_( b_( a_(starting_val) ) ); } private: A & a_; B & b_; C & c_; }; { A a; B b; C c; Pipeline<A,B,C> p(a,b,c); ... ... ... int arg(10); p(arg); } On 11/3/06, Fernando Cacciola <fernando_cacciola@hotmail.com> wrote:

Bryan Ewbank wrote:
Perhaps I'm misunderstanding or oversimplifying, but doesn't this work?
Of course it does... for a fixed set of 3 functors. The idea was that the code recieves an arbitrary tuple of functors (that is, any type and number) and creates the pipe programmatically. Best Fernando Cacciola
participants (5)
-
"JOAQUIN LOPEZ MU?Z"
-
Arkadiy Vertleyb
-
Bryan Ewbank
-
Fernando Cacciola
-
Peter Dimov