Boost logo

Boost Users :

Subject: Re: [Boost-users] [lamda] smart self binding of a function object
From: OvermindDL1 (overminddl1_at_[hidden])
Date: 2010-05-12 04:42:30


On Tue, May 11, 2010 at 4:11 AM, alfC <alfredo.correa_at_[hidden]> wrote:
> Hi,
>
>  I usually have function-classes that take two arguments.
>
> class f{
>  double operator()(double x, double y) const { x*y+y; }
> };
>
> called as:
>
> f myf;
> cout << myf(4.,3.);
>
> for some purposes I need a function of only one variable (parametrized
> in the first or second argument. So I end up doing:
>
> using boost::function;
> using namespace boost::lambda;
> function<double(double)> myf_at5 = bind(&f::operator(), myf, 5., _1);
> // myf_at5 is myf(5.,*)
>
> So, now I can pass myf_at5 to something that accepts a function of one
> variable.
>
> root_finder( myf_at5, ...);
>
> since I have access to f I would like to make f smart enough to handle
> its own binding. Eg.
>
> class f{
>  ... // same as before
>  function<double(double)> operator()(double x_value, YYYY y_arg){
>   return bind(
>         &f::operator(), //maybe needs cast to double(*)
> (double,double)
>         *this,
>         x_value,
>         y_arg
>   );
>  }
>  function<double(double)> operator()(XXXX x_arg, double y_value){
>   return bind(
>      &f::operator(), //maybe needs cast
>      *this,
>      x_arg,
>      y_value
>   );
>  }
> };
>
> The question is: What should be the type of XXXX and YYYY?
>
> in such a way that I can just call
>
> root_finder( myf(5., _1) , ... );
> or
> more complicated things like
> root_finder( myf(5., _1 * 2.), ...);
>
> in other words,
> myf(5.,_1) is the same as the old  bind(&f::operator(), myf, 5., _1);

The way I would do this would be Boost.Phoenix, rewrite your f like (I
am not making this fully generic, although it would be easy to do,
just keeping it as doubles):

  class f_impl{
    template <typename Arg1, typename Arg2>
    struct result
    {
        typedef double type;
    };
    double operator()(double x, double y) const { x*y+y; }
  };
boost::phoenix::function<f_impl> f;

This turns f into a lazy functor, thus for immediate usage you can do:

  cout << f(4.,3.)(); // Assuming Phoenix3 (in development) with
forwarding built-in, so no val's needed.
or
  f_impl myf;
  cout << myf(4.,3.);

But allows lazy generation like:
  root_finder( f(5., _1) , ... );
or
  root_finder( f(5., _1 * 2.), ...);

If curious, Boost.Phoenix can do what lambda can, but more, it is a
generic lazy extension for C++, even something as simple as:
  val(5)
that essentially returns a function of the type int(void), so:
  cout << val(5)();
return 5 to cout. Obviously a bit of an inconvenience that the
immediate form returns a lazy adapter too, but it is the pure lazy
way, but allows for a vast amount of power and programming
capabilities.

(I have even written a few small programming projects completely in
Boost.Phoenix to see what it is like, quite fascinating, I do like it,
just hits compile time a bit hard when everything is lazy in an entire
program, but runs well).

Boost.Phoenix2 docs:
http://www.boost.org/doc/libs/1_43_0/libs/spirit/phoenix/doc/html/index.html
Boost.Phoenix3 is in development, but Phoenix2 is complete, just
missing the 'perfect' forwarding adaption.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net