【问题标题】:Using std::array as Attribute for boost::spirit::x3使用 std::array 作为 boost::spirit::x3 的属性
【发布时间】:2023-04-04 08:05:01
【问题描述】:

我正在尝试使用 boost::spirit 的最新版本 x3(包含在 boost 1.54 中)将数字列表解析为固定大小的 std::array 容器。 由于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 结合编译。这是一个错误还是我用错了? 打电话例如fusion::front(v) 没有所有 x3 代码编译和工作,所以我想我的代码并没有完全错误。

但是我确信 x3 有一个更简洁的解决方案,不涉及任何融合适配器或语义操作来解决这个简单的问题。

【问题讨论】:

  • boost::array 是一个选项吗?我相信包括 "boost/fusion/include/boost_array.hpp" double_ &gt;&gt; double_ &gt;&gt; double_ 应该可以工作。
  • 我修复了那些愚蠢的错误,对此感到抱歉。 boost::array 不是一个选项,因为我正在连接严重依赖于 std::array 的现有代码。
  • This is an awful hack 使您的方法编译。您可能应该等待一个更好的答案(或者实际上是一个好的答案)。
  • cv_and_he:我真的不明白你的代码的boost::add_reference 部分是做什么的,或者它如何解决我的编译器报告的问题,但确实如此。现在我可以接受这个 hack,因为它还允许调整任何 ADT,而不仅仅是 std::array
  • The machinery that Spirit uses to access sequence attributes,强制添加对boost::front结果的引用,以便不进行复制。遗憾的是,这不适用于BOOST_FUSION_ADAPT_ADT 使用的adt_attribute_proxy。我所做的只是让boost::add_reference 不添加对adt_attribute_proxy 的引用。我认为这甚至可能有点道理,因为它基本上是一种观点,但弄乱这些共同特征似乎不是一个好主意。

标签: c++ c++14 boost-spirit stdarray boost-spirit-x3


【解决方案1】:

您发布的代码充满了草率的错误。真的,没有理由期望那里有任何东西可以编译。

不管怎样,我把它清理干净了¹。当然你应该包括

#include <boost/fusion/adapted/array.hpp>

很遗憾,它根本不起作用。我得出了大致相同的结论(在尝试了你提到的同样的事情之后,在阅读它之前:))。

这是 Spirit X3 的可用性问题 - 仍处于实验阶段。您可以在 [spirit-general] 邮件列表中报告。响应通常非常迅速。


¹如果你想看看我用http://paste.ubuntu.com/12764268/ 工作过什么;我也使用了x3::repeat(3)[x3::double_] 进行比较。

【讨论】:

  • 很遗憾std::array 没有被融合适配。您建议的标头(或“boost/fusion/include/boost_array.hpp”)仅影响boost::arrayThis 似乎可以进行一些小的修改。 Here 是适应 std::array 的一个非常古老的尝试(我不知道它是否仍然有效)。
  • 嗯。它对我来说也不值得提升阵列。以后有时间会看看差异。
  • std::forward_list 存在类似问题。 push_back 要求类成为 Boost.Spirit 的容器。
  • 根据发行说明std::array将从Boost 1.63开始通过融合进行适配。
  • @llonesmiz,是的,现在有一个boost/fusion/adapted/std_array.hpp
猜你喜欢
  • 1970-01-01
  • 2021-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多