【问题标题】:How to parse text into a struct using boost::spirit?如何使用 boost::spirit 将文本解析为结构?
【发布时间】:2012-05-05 00:03:23
【问题描述】:

我正在学习boost::spirit,我正在尝试读取一些文本并将其解析为结构。

例如,"2: 4.6" 在下面的TestStruct 中被解析为 int 2 和 double 4.6

#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/fusion/include/std_pair.hpp>
namespace qi = boost::spirit::qi;

struct TestStruct {
  int myint;
  double mydouble;
  TestStruct() {}
  TestStruct(std::pair<int,double> p) : myint(p.first), mydouble(p.second) {}
};

template <typename Iterator, typename Skipper>
struct MyGrammar : qi::grammar<Iterator, TestStruct(), Skipper> {
  MyGrammar() : MyGrammar::base_type(mystruct) {
    mystruct0 = qi::int_ >> ":" >> qi::double_;
    mystruct = mystruct0;
  }
  qi::rule<Iterator, std::pair<int,double>(), Skipper> mystruct0;
  qi::rule<Iterator, TestStruct(), Skipper> mystruct;
};

int main() {
  typedef boost::spirit::istream_iterator It;
  std::cin.unsetf(std::ios::skipws);
  It it(std::cin), end; // input example: "2: 3.4"                                                                              

  MyGrammar<It, qi::space_type> gr;
  TestStruct ts;
  if (qi::phrase_parse(it, end, gr, qi::space, ts) && it == end)
    std::cout << ts.myint << ", " << ts.mydouble << std::endl;
  return 0;
}

它工作得很好,但我想知道如何简化这段代码?

例如我想去掉mystruct0语法规则,它只是用来标记类型std::pair&lt;int,double&gt;,然后用它来自动从mystruct规则构造TestStruct对象.

如果可能的话,我还希望能够从 std::pair 中删除 TestStruct 构造函数。

那么,下面的代码可以编译吗?那将是一个更好的解决方案:

struct TestStruct {
  int myint;
  double mydouble;
  TestStruct() {}
  TestStruct(int i, double d) : myint(i), mydouble(d) {}
};

template <typename Iterator, typename Skipper>
struct MyGrammar : qi::grammar<Iterator, TestStruct(), Skipper> {
  MyGrammar() : MyGrammar::base_type(mystruct) {
    mystruct = qi::int_ >> ":" >> qi::double_;
  }
  qi::rule<Iterator, TestStruct(), Skipper> mystruct;
};

int main() {
  typedef boost::spirit::istream_iterator It;
  std::cin.unsetf(std::ios::skipws);
  It it(std::cin), end; // input example: "2: 3.4"                                                                              

  MyGrammar<It, qi::space_type> gr;
  TestStruct ts;
  if (qi::phrase_parse(it, end, gr, qi::space, ts) && it == end)
    std::cout << ts.myint << ", " << ts.mydouble << std::endl;
  return 0;
}

不幸的是,编译器说:

boost_1_49_0/include/boost/spirit/home/qi/detail/assign_to.hpp:123: 
error: no matching function for call to ‘TestStruct::TestStruct(const int&)’

【问题讨论】:

    标签: c++ parsing boost boost-spirit boost-spirit-qi


    【解决方案1】:

    为了能够将值“按顺序”解析为结构,您需要将其转换为 fusion 元组,如 here 所述。

    在你的情况下,这意味着你需要

    1. 包括必要的标题

      #include <boost/fusion/adapted/struct/adapt_struct.hpp>
      
    2. 使用 fusion-adapt 结构宏。最好把它放在TestStruct的声明之后

      BOOST_FUSION_ADAPT_STRUCT(
              TestStruct,
              (int,myint)
              (double,mydouble)
           )
      

    通过这两个更改,您的简化版本可以编译并产生所需的结果。不确定它现在是否真的更简单了——但如果您打算在结构中添加更多成员,这是一个很好的起点,因为它可能有助于将来简化事情。

    我没有看到您可以进行任何其他重大更改来简化程序。

    【讨论】:

      【解决方案2】:

      是的,可以编译代码。事实上,你可以不用构造函数:默认的(编译器生成的)构造函数就可以了。

      您需要做的就是将您的结构调整为融合序列。 (作为奖励,这也适用于业力。)
      这正是使 std::pair 发挥作用的魔力。

      #include <iostream>
      #include <boost/spirit/include/qi.hpp>
      #include <boost/fusion/adapted/struct.hpp>
      namespace qi = boost::spirit::qi;
      
      struct TestStruct {
          int myint;
          double mydouble;
      };
      
      BOOST_FUSION_ADAPT_STRUCT(TestStruct, (int, myint)(double, mydouble));
      
      template <typename Iterator, typename Skipper>
      struct MyGrammar : qi::grammar<Iterator, TestStruct(), Skipper> {
          MyGrammar() : MyGrammar::base_type(mystruct) {
              mystruct = qi::int_ >> ":" >> qi::double_;
          }
          qi::rule<Iterator, TestStruct(), Skipper> mystruct;
      };
      
      int main() {
          typedef std::string::const_iterator It;
          const std::string input("2: 3.4");
          It it(input.begin()), end(input.end());
      
          MyGrammar<It, qi::space_type> gr;
          TestStruct ts;
      
          if (qi::phrase_parse(it, end, gr, qi::space, ts) && it == end)
              std::cout << ts.myint << ", " << ts.mydouble << std::endl;
      
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多