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
source to share
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
source to share