Разбор с использованием Boost Spirit в вектор STL - PullRequest
0 голосов
/ 29 апреля 2018

Я изучаю Boost Spirit 2 и не могу понять, почему не могу разобрать последовательность из двух целых чисел в вектор STL типа int. Из документации оператора >> ( здесь ) я знаю, что атрибут грамматики int_ >> int_ должен быть vector<int>. А из документации обозначений атрибутов я знаю, что "запись vector<A> обозначает любой контейнер STL , содержащий элементы типа A".

И все же, когда я пытаюсь добавить действие к int_ >> int_, которое принимает std::vector в качестве атрибута, компиляция завершается неудачей.

Среди других сообщений об ошибках написано: /usr/include/boost/bind/mem_fn_template.hpp:163:7: note: no known conversion for argument 2 from ‘boost::fusion::vector<int, int>’ to ‘const std::vector<int>&’

Мне известен этот вопрос («Получение boost :: spirit :: qi для использования контейнеров stl»), но решение, в том числе std_tuple.hpp, ничего не изменило.

Почему это?

#include <iostream>
#include <string>
#include <vector>

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/bind.hpp>

namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    class ParserActions
    {
    public:
        void printivec (std::vector<int> const& ivec)
        {
            std::cout << "We see " << ivec.size() << " integers" << std::endl;
        }
    };

    template <typename Iterator>
    bool parse_ivec(Iterator first, Iterator last)
    {
        using ascii::space;

        ParserActions actionContainer;

        auto two_ints = (qi::int_ >> qi::int_);

        bool r = qi::parse(
            first,                          /*< start iterator >*/
            last,                           /*< end iterator >*/
            two_ints[boost::bind(&ParserActions::printivec,&actionContainer,_1)]
            );

        return first == last && r;
    }
}

int main()
{
    std::string str = "12 13";

    if (client::parse_ivec(str.begin(),str.end()))
        std::cout << "Parsing succeeded\n";
    else
        std::cout << "Parsing failed!\n";

    return 0;
}

1 Ответ

0 голосов
/ 29 апреля 2018

int_ >> int_ синтезирует кортеж int, int.¹

Если вы хотите принудительно синтезировать контейнер, сделайте его repeat(2) [ int_ ], чтобы выразить это.

Sidenote : Как вы увидите ниже, есть место для совместимости атрибутов, даже если связанный атрибут является дополнительным, поэтому вам не нужно.

Sidenote : auto с выражениями синтаксического анализатора запрашивает неопределенное поведение: Назначение синтаксических анализаторов для авто переменных

Sidenote : ваш ввод использует разделитель пробелов, а анализатор - нет. Это никогда не сработает.

Ваш пример кода, похоже, не имеет ничего общего с целью, поэтому вот мой маленький пример:

1. vector<int>:

Live On Coliru

#include <boost/spirit/include/qi.hpp>
using Vec = std::vector<int>;
namespace qi = boost::spirit::qi;

template <typename It> Vec parse_ivec(It first, It last) {
    Vec v;
    if (qi::phrase_parse(first, last,  qi::int_ >> qi::int_ >> qi::eoi, qi::space, v))
        return v;
    throw std::runtime_error("Parse failed");
}

Vec parse_ivec(std::string const& r) { return parse_ivec(begin(r), end(r)); }

int main() {
    for (int i : parse_ivec("12 13")) {
        std::cout << i << "\n";
    }
}

печать

12
13

2. Адаптированные структуры

В качестве альтернативы, если вам нужна структура, не std::vector<>:

Live On Coliru

#include <boost/fusion/adapted/struct.hpp>
struct Vec { int a, b; };
BOOST_FUSION_ADAPT_STRUCT(Vec, a, b)

#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;

template <typename It> Vec parse_ivec(It first, It last) {
    Vec v;
    if (qi::phrase_parse(first, last,  qi::int_ >> qi::int_ >> qi::eoi, qi::space, v))
        return v;
    throw std::runtime_error("Parse failed");
}

Vec parse_ivec(std::string const& r) { return parse_ivec(begin(r), end(r)); }

int main() {
    Vec vec = parse_ivec("12 13");
    std::cout << vec.a << " " << vec.b << "\n";
}

печать

12 13

3. std::tuple<int, int>

Live On Coliru

#include <boost/fusion/adapted/std_tuple.hpp>
using Vec = std::tuple<int, int>;

#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;

template <typename It> Vec parse_ivec(It first, It last) {
    Vec v;
    if (qi::phrase_parse(first, last,  qi::int_ >> qi::int_ >> qi::eoi, qi::space, v))
        return v;
    throw std::runtime_error("Parse failed");
}

Vec parse_ivec(std::string const& r) { return parse_ivec(begin(r), end(r)); }

int main() {
    Vec vec = parse_ivec("12 13");
    std::cout << std::get<0>(vec) << " " << std::get<1>(vec) << "\n";
}

печать

12 13

¹ Технически, последовательность Fusion, которая может быть сделана совместимой с множеством типов, таких как std :: pair, или ваши собственные типы адаптированы.

...