I am trying to parse a list of numbers into a container with a fixed size std::array using boost :: spirit latest release x3 (as included in boost 1.54). Since std::array has the necessary functions, it is defined as a Container, but there is no insert function in it, which makes it incompatible. Here is a brief example of what I'm 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 will not compile since std::array does not have an 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 of this. 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 merge sequence using BOOST_FUSION_ADAPT_ADT as follows:
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 not to treat std :: array as a container:
namespace boost { namespace spirit { namespace x3 { namespace traits { template<> struct is_container<Vertex> : public mpl::false_ {}; }}}}
But this will not compile in conjunction with x3. Is this a mistake or am I using it incorrectly? A call, for example. fusion::front(v) without compiling and running all x3 code, so I think my code is not quite right.
However, I am sure that there is a pure solution with x3 that does not include any adapters or semantic actions for this simple problem.