Boost.Spirit - Как использовать повтор для разбора в структуру?

Я пытаюсь создать небольшую программу для анализа информации об использовании процессора из /proc/stat с помощью Boost.Spirit. В основном это работает, но я не могу заставить мою грамматику компилироваться при использовании 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 работает нормально, но я хотел бы знать, что я делаю неправильно с повторением.

Я также могу заставить повтор работать, если я заменю структуру процессора на вектор беззнаковых целых.

1 ответ

Решение

Ты не можешь Без труда. Это потому что 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. Там также ответ, который описывает, как заставить его работать с 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 там недоступен).
  • Лямбда-трюк, чтобы сделать using namespace при возможности вернуть значение для ok,
Другие вопросы по тегам