Boost logo

Boost :

From: Giovanni Piero Deretta (gpderetta_at_[hidden])
Date: 2008-03-28 23:13:12


One thing that has always bothered me of the various boost lambda
abstractions (be them compile time lambdas a-la mpl or runtime
lambdas a-la Boost.Lambda, phoenix or plain bind) is that you must use
non descriptive names for your argument paceholders.

What I would like is to be able to declare the names of the formal
parameters of my lambdas.

Sure, in mpl you can have your placeholder names by typedef-ing the
standard placeholders to a new name;
with runtime lambdas, you can create custom objects with the same type
of standard placeholders.
In all those cases you still need to declare them outside of the
lambda expression.

While reading the Proto example "Vector: Adapting a New Terminal
Type", I discovered something new about C++:
you can forward declare class names inside a template parameter
declaration. That is, something like this is actually possible:

  void foo () {
    int i =
     lambda
      // introduce formal parameter names
      [ _<class left>(),
         _<class right>()
      ]
      // now use them!
      [_<left>() + _<right>()]
      // actual parameters values
     ( 10, 20 );
  }

The _<...>() looks a bit clumsy, but it might be actually usable.

I think that such a trick might really shine with the so called "round lambda"s;
in the past I have toyed with a template class 'compose' that used the
round lambda syntax for functional composition:

Assume you have two polymorphic function objects types that work on
ranges called 'fold' and 'reverse' (which do the obvious thing implied
by their names):

  struct reverse_fold {
    template<typename Sig> struct result;

    template<class Range, class Init, class Op>
    struct result<reverse_fold(Range, Init, Op)> {
    private:
      typedef typename boost::result_of<reverse(Range)>::type reversed;
    public:
      typedef typename boost::resuld_of<fold(reversed, Init, Op)>::type type;
    };

    template<class Range, class Init, class Op>
    typedef typename result<reverse_fold(Range, Init, Op)>::type
    operator()(Range const& range, Init i, Op op) const {
      return fold()(reverse()(range), i, op);
    }
  };

could be rewritten, using 'compose', as:

typedef compose<fold(reverse(_1), _2, _3> reverse_fold;

Which saves quite a bit of typing! (of course it works only with
stateless function objects).
Still the non-descriptive _N placeholders bother me.
Using the named placeholder trick it would become:

  typedef compose<
    // introduce formal args names
    args<
      class range
    , class init
    , class op
>
    // expression
  , fold(reverse(range), init, op)
    // function name
> reverse_fold;

With complex expressions, this could be quite a readability improvement.
Except for confirming that the above expression does actually compile
(at least with gcc), I have yet to try to implement it,
but I think it should be fairly easy.

Comments?

-- 
gpd

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk