I'm trying to parse a list of numbers into a fixed sized std::array
container using boost::spirit's newest release x3 (as included in boost 1.54).
Since std::array
has the necessary functions, it is detected as an Container, but it is lacking the insert function which makes it incompatible.
Here is a short example of what I am trying to accomplish:
#include <boost/spirit/home/x3.hpp>
#include <array>
#include <iostream>
#include <string>
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
typedef std::array<double, 3> Vertex;
int main(int, char**) {
using x3::double_;
using ascii::blank;
std::string input = "3.1415 42 23.5";
auto iter = input.begin();
auto vertex = x3::rule<class vertex, Vertex>{} =
double_ >> double_ >> double_;
Vertex v;
bool const res = x3::phrase_parse(iter, input.end(), vertex, blank, v);
if (!res || iter != input.end()) return EXIT_FAILURE;
std::cout << "Match:" << std::endl;
for (auto vi : v) std::cout << vi << std::endl;
return EXIT_SUCCESS;
}
This won't compile since std::array
has no insert
function.
As a workaround I used semantic actions:
auto vertex() {
using namespace x3;
return rule<class vertex_id, Vertex>{} =
double_[([](auto &c) { _val(c)[0] = _attr(c); })] >>
double_[([](auto &c) { _val(c)[1] = _attr(c); })] >>
double_[([](auto &c) { _val(c)[2] = _attr(c); })];
}
and then call
x3::phrase_parse(iter, input.end(), vertex(), blank, v);
instead. This works (using clang 3.6.0 with -std=c++14), but I think this solution is very inelegant and hard to read.
So I tried to adapt std::array as a fusion sequence using BOOST_FUSION_ADAPT_ADT
like so:
BOOST_FUSION_ADAPT_ADT(
Vertex,
(double, double, obj[0], obj[0] = val)
(double, double, obj[1], obj[1] = val)
(double, double, obj[2], obj[2] = val))
and then specializing x3::traits::is_container
for Vertex to tell x3 to not treat std::array as a container:
namespace boost { namespace spirit { namespace x3 { namespace traits {
template<> struct is_container<Vertex> : public mpl::false_ {};
}}}}
But this won't compile in combination with x3. Is this a bug or am I using it wrong?
Calling e.g. fusion::front(v)
without all the x3 code compiles and works, so I guess my code is not completely wrong.
However I'm sure there is a cleaner solution with x3 not involving any fusion adaptors or semantic actions for this simple problem.
The code you posted is riddled with sloppy errors. There's no reason to expect anything in there to compile, really.
Regardless, I cleaned that up¹. Of course you should have included
#include <boost/fusion/adapted/array.hpp>
Sadly it simply doesn't work. I reached largely the same conclusion as (after trying the same things you mention, before reading about it :)).
This is a usability issue with Spirit X3 - which is still in experimental phase. You could report it at the [spirit-general] mailing list. Response is usually pretty swift.
¹ in case you want to see what I worked with http://paste.ubuntu.com/12764268/; I've also used x3::repeat(3)[x3::double_]
for comparison.