std::array
我正在尝试使用 boost::spirit 的最新版本 x3(包含在 boost 1.54 中)将数字列表解析为固定大小的容器。由于std::array
具有必要的功能,因此被检测为Container,但缺少插入功能,使其不兼容。这是我要完成的一个简短示例:
#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
功能。作为一种解决方法,我使用了语义操作:
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);
反而。这有效(使用带有-std = c ++ 14的clang 3.6.0),但我认为这个解决方案非常不雅且难以阅读。
所以我尝试使用BOOST_FUSION_ADAPT_ADT
如下方式将 std::array 改编为融合序列:
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 视为容器:
namespace boost { namespace spirit { namespace x3 { namespace traits {
template<> struct is_container<Vertex> : public mpl::false_ {};
}}}}
但这不会与 x3 结合编译。这是一个错误还是我用错了?在没有所有 x3 代码的情况下调用 egfusion::front(v)
可以编译和工作,所以我想我的代码并不是完全错误的。
但是我确信对于这个简单的问题,x3 有一个更清洁的解决方案,不涉及任何融合适配器或语义操作。