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
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... 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,
"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; } **********************

Fernando Cacciola wrote:
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 )
You probably need Functor here, not some pointer to function.
,typename _bi::list_av_1<bind_argument_type>::type > type ; } ;

Hi Peter,
Fernando Cacciola wrote:
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 )
You probably need Functor here, not some pointer to function.
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:
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
You should take a look at the R, F and L that the compiler should have expanded after the error message. There may be another mismatch there.

Peter Dimov wrote:
Fernando Cacciola wrote:
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
You should take a look at the R, F and L that the compiler should have expanded after the error message. There may be another mismatch there.
Ha OK. I'll look into it next week. Besides the error, that's the general way to go? (when I can only use tuple/bind of course) 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
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: [...]
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:
Hi people
3 years of C# programming is eroding my metaprogramming habilities :(
Say I have a few arbitrary function objects:
A a ; B b ; C c ;
I can easily pipe them together 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 arbitrary 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.

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

"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.
Right. OTOH.... Can't you just use PP, and simply generate overloads? Regards, Arkadiy
participants (5)
-
"JOAQUIN LOPEZ MU?Z"
-
Arkadiy Vertleyb
-
Bryan Ewbank
-
Fernando Cacciola
-
Peter Dimov