From what I compile by reading the source and the mailing list, Phoenix does not integrate into X3 at all: the reason is that C ++ 14 makes most of them obsolete.
I agree that this leaves a few places where Qi used elegant solutions, for example. eps(DEFERRED_CONDITION) , lazy(*RULE_PTR) ( Nabialek trick ), and indeed, this case.
Spirit X3 is still under development, so we can see this added number <
Spirit X3 currently has one generic stateful context tool. This essentially replaces locals<> , in some cases inherited arguments, and the number of elements can be / done / checked in this particular case:
Here you can use it:
with<_n>(std::ref(n)) [ omit[uint_[number] ] >> *(eps [more] >> int_) >> eps [done] ]
Here _n is the type of tag that identifies the context element to search with get<_n>(cxtx) .
Note that we must currently use the reference wrapper for lvalue n , because with<_n>(0u) will result in a constant element within the context. I believe this is also a QoI that can be removed when X # matures
Now, for semantic actions:
unsigned n; struct _n{}; auto number = [](auto &ctx) { get<_n>(ctx).get() = _attr(ctx); };
It stores the parsed unsigned number in the context. (In fact, due to the ref(n) binding, it is not actually part of the context at the moment, as mentioned)
auto more = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) > _val(ctx).size(); };
Here we check that we are not really "complete", i.e. more integers allowed
auto done = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) == _val(ctx).size(); };
Here we check that we are "complete", i.e. more integers are not allowed.
Putting it all together:
Live on coliru
#include <string> #include <iostream> #include <iomanip> #include <boost/spirit/home/x3.hpp> int main() { for (std::string const input : { "3 1 2 3", // correct "4 1 2 3", // too few "2 1 2 3", // too many // " 3 1 2 3 ", }) { std::cout << "\nParsing " << std::left << std::setw(20) << ("'" + input + "':"); std::vector<int> v; bool ok; { using namespace boost::spirit::x3; unsigned n; struct _n{}; auto number = [](auto &ctx) { get<_n>(ctx).get() = _attr(ctx); }; auto more = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) > _val(ctx).size(); }; auto done = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) == _val(ctx).size(); }; auto r = rule<struct _r, std::vector<int> > {} %= with<_n>(std::ref(n)) [ omit[uint_[number] ] >> *(eps [more] >> int_) >> eps [done] ]; ok = phrase_parse(input.begin(), input.end(), r >> eoi, space, v); } if (ok) { std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout << v.size() << " elements: ", " ")); } else { std::cout << "Parse failed"; } } }
What prints:
Parsing '3 1 2 3': 3 elements: 1 2 3 Parsing '4 1 2 3': Parse failed Parsing '2 1 2 3': Parse failed Parsing ' 3 1 2 3 ': 3 elements: 1 2 3
¹ provide your support / vote on the [spirit-general] mailing list :)
² cannot find a suitable link for documentation, but it is used in some samples