Spirit.X3: использование черт push_back_container с анализатором списка - PullRequest
0 голосов
/ 04 июня 2018

У меня есть класс с публичным ctor и некоторым методом add ():

class object
{
    object() {}
    template <typename>
    void add(T&& val) { // some adding here}
}

Главный вопрос, с которым я сталкиваюсь, это как я могу использовать анализатор списка spirit.x3 для использования object :: add () вместо std :: vector <> :: push_back?

Я легко смог добиться того, что мне нужно, с помощью простого

x3 :: int_% ','

синтаксический анализатор ( live demo ), использующий следующий код:

#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <vector>

namespace x3 = boost::spirit::x3;

namespace parse_to_object
{
    struct object
    {
        using value_type = int;

        object() { std::cout << "object::object() - invoked" << std::endl; }
        void add(value_type val) { _data.push_back(val); }

        std::vector<value_type> _data;
    };

    const x3::rule<struct Test, object> r_ints("r_ints");
    const auto r_ints_def = x3::int_  % ',';
    BOOST_SPIRIT_DEFINE(r_ints);
}

namespace boost { namespace spirit { namespace x3 { namespace traits {        
template<>
struct push_back_container<parse_to_object::object>
{
    template<typename T>
    static bool call(parse_to_object::object& obj, T&& val)
    {
        obj.add(std::move(val));
        return true;
    }
};
}}}}

int main()
{
    const std::string text("1,2,3,4");

    auto begin = std::begin(text);
    const auto end = std::end(text);

    parse_to_object::object result;
    const auto ok = x3::phrase_parse(begin, end, parse_to_object::r_ints,    x3::space, result);

    std::cout << "ok = " << std::boolalpha << (ok && begin == end) << std::endl;
    std::copy(result._data.begin(), result._data.end(), std::ostream_iterator<int>(std::cout, " "));
    return 0;
}

Но, к сожалению, когда я попробовал более скомпилированный пример, такой как

'{' >> x3 :: int_ >> ':' >> x3 :: int_ >> '}')% ','

Я получаю ошибку компиляции ( live демо ):

/ opt / wandbox / boost-1.67.0 / clang-head / include / boost / spirit / home / x3 / support / traits / container_traits.hpp:102: 45: ошибка: нет типа с именем 'iterator' в 'parse_to_object :: object': mpl :: identity {};

Может ли кто-нибудь помочь с признаками spirit.x3 и привести пример того, какabopt пользовательский класс, который будет использоваться вместо std :: vector <> для анализатора списка?

1 Ответ

0 голосов
/ 04 июня 2018

В конце концов, все дело в отсутствующем:

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

std::pair по умолчанию не адаптировано.

Примечание: std::move должно быть std::forward<T> с «универсальными ссылками» (или совершенной пересылкой)

Live On Coliru

#define BOOST_SPIRIT_X3_DEBUG

#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <vector>

namespace x3 = boost::spirit::x3;

namespace parse_to_object
{
    struct object
    {
        using value_type = std::pair<int,int>;

        object() { std::cout << "object::object() - invoked" << std::endl; }
        void add(value_type val) { _data.push_back(std::move(val)); }

        std::vector<std::pair<int,int>> _data;
    };

    const x3::rule<struct Test, object> r_ints("r_ints");
    const auto r_ints_def = ('{' >> x3::int_ >> ':' >> x3::int_ >> '}') % ',';
    BOOST_SPIRIT_DEFINE(r_ints)
}

namespace boost { namespace spirit { namespace x3 { namespace traits {

    template<> struct push_back_container<parse_to_object::object>
    {
        template<typename T>
        static bool call(parse_to_object::object& obj, T&& val)
        {
            obj.add(std::forward<T>(val));
            return true;
        }
    };

}}}}

int main()
{
    const std::string text("{1:2},{3:4}");

    auto begin = std::begin(text), end = std::end(text);

    parse_to_object::object result;
    auto ok = phrase_parse(begin, end, parse_to_object::r_ints >> x3::eoi, x3::space, result);

    std::cout << "ok = " << std::boolalpha << ok << "\n";
    for (auto& p : result._data)
        std::cout << "{" << p.first << ", " << p.second << "} ";
    std::cout << "\n";
}

Отпечатки

object::object() - invoked
<r_ints>
  <try>{1:2},{3:4}</try>
  <success></success>
  <attributes></attributes>
</r_ints>
ok = true
{1, 2} {3, 4} 
...