问题描述
我试图使用boost :: spirit的最新版本x3(包括在boost 1.54中)将一组数字解析为固定大小的 std :: array
。
由于 std :: array
有必要的功能,它被检测为一个Container,但它缺少插入函数,使它不兼容。
这里是我想要完成的一个简单的例子:
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;
}
这不会编译,因为 std :: array
没有 insert
函数。作为解决方法我使用语义动作:
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); })];
}
然后调用
x3::phrase_parse(iter, input.end(), vertex(), blank, v);
。这工作(使用clang 3.6.0与-std = c ++ 14),但我认为这个解决方案是非常不起眼,很难阅读。
instead. This works (using clang 3.6.0 with -std=c++14), but I think this solution is very inelegant and hard to read.
所以我试图使用 BOOST_FUSION_ADAPT_ADT
,将std :: array作为融合序列使用:
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))
然后专门化 x3 :: traits :: is_container
为Vertex告诉x3不将std :: array当作容器:
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_ {};
}}}}
但这不会与x3结合编译。这是一个错误还是我使用它错了吗?
fusion :: front(v)
没有所有的x3代码编译和工作,所以我猜我的代码不是完全错误。
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.
但我确定有一个更清洁的解决方案,x3不涉及任何融合适配器或语义动作这个简单的问题。
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.
无论如何,我清理了up¹。当然,您应该已经包括
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 :)).
这是Spirit X3的可用性问题 - 仍处于实验阶段。你可以在[精神]邮件列表上报告。回应通常很漂亮。
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.
¹如果您想要查看我的工作;我还使用 x3 :: repeat(3)[x3 :: double _]
进行比较。
¹ 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.
这篇关于使用std :: array作为boost :: spirit :: x3的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!