Boost logo

Boost Users :

Subject: Re: [Boost-users] [Proto] Processing Lists
From: Eric Niebler (eric_at_[hidden])
Date: 2010-02-23 04:02:32


Hi David,

On 2/22/2010 10:29 PM, David Greene wrote:
> I want to process a list that looks something like this:
>
> struct List : or_<
> comma<
> List,
> Item
> >,
> Item
>> {};
>
> But rather than processing each item separately, I want to pass a fusion (or
> some other) sequence to a semantic action:
>
> when<
> List,
> SomeAction(...)
>> {};
>
> Ideally the argument to SomeAction would be a fusion sequence but I don't
> know how to produce one. This doesn't work:
>
> when<
> List,
> SomeAction(flatten(_))
>> {};
>
> because flatten is not a transform.

You were SO close. You want proto::functional::flatten here (the type of
a function object), not proto::flatten (an ordinary function).

> I don't want to use fold_tree because I
> don't want to actually fold the sequence. SomeAction is something like this:
>
> struct SomeAction : callable {
> template<typename Seq>
> void operator()(Seq range) {
> typedef ... iterator;
>
> // Is this legal for fusion sequences?
> for(iterator i = begin(range), iend = end(range);
> i != iend;
> i = next(i)) {
> ...
> }
> }
> }
>
> Is there a way to do this?

Try this:

   #include <iostream>
   #include <boost/fusion/include/for_each.hpp>
   #include <boost/proto/proto.hpp>

   using namespace std;
   using namespace boost;
   using namespace boost::proto;

   struct display_value {
     typedef void result_type;
     template<typename Item>
     void operator()(Item i) const {
       cout << value(i) << ' ';
     }
   };

   struct SomeAction : callable {
     typedef void result_type;
     template<typename Seq>
     void operator()(Seq const &range) {
       // Use fusion algorithms to process the list.
       fusion::for_each(range, display_value());
     }
   };

   struct Item : terminal<_> {};

   struct List : or_<
     comma<
       List,
       Item
>,
     Item
> {};

   struct ProcessList : when<
     List,
     SomeAction(functional::flatten(_))
> {};

   int main()
   {
     ProcessList()((lit(1), 2, 3, 4));
   }

> On a related note, I know I can use varag<> to match a function call
> expression with an arbitrary number of operands and invoke a transform
> on each operand. But how would I generate a fusion sequence of all
> the operands? In other words, with:
>
> proto::function< X, proto::vararg<Y> >
>
> how do I talk about the vararg<> part in a semantic action? CalculatorGrammar
> has a use of vararg but it uses fold<> to process it. I don't want to fold a
> sequence, I want to pass it to a transform.

Manjunath already answered this one. Proto expressions already are
fusion sequences, and proto::_expr returns the current expression. You
can use proto::functional::pop_front in a transform to pop off the first
bit (the thing that matches X in your example) and pass the result to
something that accepts fusion sequences.

HTH,

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com

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