Using std::array as Attribute for boost::spirit::x3

江枫思渺然 提交于 2019-12-21 04:40:25

问题


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.


回答1:


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.



来源:https://stackoverflow.com/questions/33082427/using-stdarray-as-attribute-for-boostspiritx3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!