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.
boost::array
an option? I believe including "boost/fusion/include/boost_array.hpp"double_ >> double_ >> double_
should work. – Nielaboost::array
is not an options since I am interfacing existing code that relies heavily onstd::array
. – Chondroboost::add_reference
part of your code does, or how it solves the issues my compiler reports, but it does. For now I can live with that hack since it also allows adapting any ADT, not juststd::array
. – Chondroboost::front
in order to not make copies. This sadly does not work with theadt_attribute_proxy
thatBOOST_FUSION_ADAPT_ADT
uses. What I did is simply makeboost::add_reference
not add a reference to anadt_attribute_proxy
. I think this may even make a bit of sense since it is basically a view, but messing with such common traits hardly seems like a good idea. – Niela