Boost.Spirit - 如何使用重复解析为结构

Boost.Spirit - How to use repeat to parse into a struct?

本文关键字:结构 Spirit 何使用 Boost      更新时间:2023-10-16

我正在尝试制作一个小程序来使用 Boost.Spirit 解析来自/proc/stat 的 cpu 使用信息。它大部分工作,但是在使用repeat时我无法编译语法。我错过了什么?

整个代码:

#include <vector>
#include "boost/fusion/include/adapt_struct.hpp"
#define BOOST_SPIRIT_DEBUG
#include "boost/spirit/include/qi.hpp"
#include "boost/iostreams/device/mapped_file.hpp"
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct Cpu
{
   unsigned int user;
   unsigned int nice;
   unsigned int system;
   unsigned int idle;
   unsigned int iowait;
   unsigned int irq;
   unsigned int softirq;
   unsigned int steal;
   unsigned int guest;
   unsigned int guest_nice;
};
BOOST_FUSION_ADAPT_STRUCT(
   Cpu,
   (unsigned int, user)
   (unsigned int, nice)
   (unsigned int, system)
   (unsigned int, idle)
   (unsigned int, iowait)
   (unsigned int, irq)
   (unsigned int, softirq)
   (unsigned int, steal)
   (unsigned int, guest)
   (unsigned int, guest_nice)
)
template< typename Iter, typename Skip = ascii::blank_type >
struct Cpu_parser : qi::grammar< Iter, Cpu(), Skip >
{
   qi::rule< Iter, Cpu(), Skip > start;
   Cpu_parser() : Cpu_parser::base_type(start)
   {
      using namespace qi;
      start = lexeme[lit("cpu") >> omit[-uint_]] >> repeat(10)[uint_];
      //start = lexeme[lit("cpu") >> omit[-uint_]] >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_;
      BOOST_SPIRIT_DEBUG_NODE(start);
   }
};
int main(int argc, char** argv)
{
   std::vector< Cpu > cpus;
   {
      std::ifstream ifs("/proc/stat");
      ifs >> std::noskipws;
      Cpu_parser< boost::spirit::istream_iterator > cpu_parser;
      std::cout << phrase_parse(
         boost::spirit::istream_iterator(ifs),
         boost::spirit::istream_iterator(),
         cpu_parser % qi::eol,
         ascii::blank,
         cpus) << std::endl;
   }
   return 0;
}
带有

所有单个uint_s的注释行工作正常,但我想知道重复我做错了什么。

如果我用无符号整数向量替换 CPU 结构,我也可以重复工作。

你不能。容易。这是因为repeat()[]合成容器属性。您的结构是一个融合序列,而不是一个容器。

你/可以/假装它

  1. 不使用FUSION_ADAPT_STRUCT
  2. 定义自定义点(例如 is_container<Cpu> .这里有一个示例描述了文档中如何执行操作:http://www.boost.org/doc/libs/1_60_0/libs/spirit/doc/html/spirit/advanced/customize/iterate/container_iterator.html#spirit.advanced.customize.iterate.container_iterator.example。还有一个答案描述了如何使其与std::array一起工作(

不过,有个好消息:


"好消息">

对于融合序列,qi::auto_解析器知道该怎么做!

这样可以去除80%的脂肪:

住在科里鲁

#include "boost/fusion/include/adapt_struct.hpp"
#include "boost/spirit/include/qi.hpp"
#include <fstream>
struct Cpu {
   unsigned user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice;
};
BOOST_FUSION_ADAPT_STRUCT(Cpu, user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice)
int main() {
    std::vector<Cpu> cpus;
    bool ok = [&cpus] {
        using It = boost::spirit::istream_iterator;
        using namespace boost::spirit::qi;
        std::ifstream ifs("/proc/stat");
        return parse(
                It(ifs >> std::noskipws), {},
                ("cpu" >> -omit[uint_] >> skip(blank)[auto_]) % eol,
                cpus);
    }();
    std::cout << std::boolalpha << ok << std::endl;
}

注意

  • 输出为 true 。只是不在 Coliru 上(那里无法访问/proc/cpu(。
  • lambda 技巧是为了使using namespace作用域化,同时能够返回 ok 的值。