问题
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