Boost :: spirit conveying semantic actions in inherited attributes

I am trying to pass a semantic action in a grammatical inherited argument.

In the most basic example below, the grammar parses two numbers and I am passing in a semantic action (in C ++ lambda form) and I would like this action to be called when parsing the first number. However, it is not called, but silently ignored, and I would like to know why this is the case and what is the correct way to do things like this.

#include <iostream>
#include <boost/spirit/include/qi.hpp>

using namespace std;
using namespace boost;

namespace qi = spirit::qi;
namespace phx = phoenix;

template <typename Iterator, typename Action>
struct two_numbers : qi::grammar<Iterator, void (Action const&)>
{
  two_numbers() : two_numbers::base_type(start)
  {
    using namespace qi;
    start = int_ [ _r1 ] >> ' ' >> int_;
  }
  qi::rule<Iterator, void (Action const&)> start;
};

int main ()
{
  string input { "42 21" };
  auto first=std::begin (input), last=std::end(input);

  static const auto my_action = [] (auto&& p) {
    cout << "the meaning of life is " << p << "\n";
  };

  static const two_numbers <decltype(first), decltype (my_action)> p;

  if (qi::parse (first, last, p(phx::ref(my_action))))
    cout << "parse ok\n";
}

      

Expected Result:

the meaning of life is 42
parse ok

      

And the real conclusion:

parse ok

      

+3


source to share


1 answer


First, the immediate answer:

"I am trying to convey a semantic action in a grammatical inherited argument."

instant traumatic shock. You ... you ... what ?!

C ++ is not very good for higher order programming, certainly not with static polymorphism based on expression templates. This is actually the case, but in my previous answer, I already warned against UB when storing expression templates in named objects (โ‰… variables).

At the time, it was the UB that you noticed. This, in my opinion, was lucky.

I recently came across another question about similar targets:

Pay particular attention to the flow of comments. I don't think this is a sane way, at least until Boost Mpl is done with the full goodness of C ++ 11 ( Boost Hana , maybe?) And Proto-0x .

By then, Spirit X3 is probably mature and we're just left with a Boost Phoenix gap. I'm not sure if this is on any agenda.



In short: we will be stuck in this "half-empty" land where we can have good things, but with some rather limited limitations. We should probably avoid getting carried away and pretend that we can write Haskell in C ++.

Also relevant: there is a proposal ( N4221, pdf ) for a generalized lifetime extension of C ++ references. It comes with some good examples of simple applications like Boost Range adapters, which are quiet UB in current C ++. For example. from ยง 2.3 Universal observation:

std::vector<int> vec;
for (int val : vec | boost::adaptors::reversed
                   | boost::adaptors::uniqued) 
{
       // Error: result of (vec | boost::adaptors::reversed) died.
}

      


Decision

However, since the inherited argument will be a functor (not a lazy actor), you need to chain it:

    start = int_ [ phx::bind(phx::cref(_r1), qi::_1) ] >> ' ' >> int_;

      

It Works: Live On Coliru

However, I do not recommend this

+4


source







All Articles