парсинг boost::spirit в структуру с помощью std::array

Я использую boost::spirit для анализа текста в структуру, содержащую массив фиксированного размера. Следуя примеру в

qi/boost_array.cpp

и пытаясь использовать его для синтаксического анализа в структуру, содержащую std::array (или boost::array), я понял, что из-за того, как работает BOOST_FUSION_ADAPT_STRUCT, я должен разместить вспомогательную функцию result_of: :adapt_array‹ some_array_type >::type в структуре.

Я думаю, что должна быть возможность создать оболочку с помощью BOOST_FUSION_ADAPT_ADT, но кажется излишним просто избавиться от небольших накладных расходов адаптера в структуре. Поскольку у меня не так много примеров, я могу жить с этим с точки зрения памяти, но это также вносит некоторый шум.

Я также думаю, что было бы возможно создать адаптер, производный от типа массива, а не инкапсулировать его, чтобы скрыть часть шума, но это заставит меня изменить все существующие структуры, и это приведет к утечке накладных расходов синтаксического анализатора наружу, что не является хорошее решение.

Есть ли что-то очевидное, что я приближаюсь неправильно, или существуют новые помощники, которые направляют накладные расходы в фоновом режиме, чтобы их можно было инкапсулировать в синтаксическом анализаторе?

Мне известно об использовании std::array в качестве атрибута для boost::spirit::x3 .

Живой пример

Вот мой текущий код:

#include <string>
#include <array>
#include <boost/spirit/include/qi.hpp>

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

// ...code from http://www.boost.org/doc/libs/1_60_0/libs/spirit/example/qi/boost_array.cpp here

typedef result_of::adapt_array<std::array<double, 6> >::type AdaptedArrayType;

struct StructWithArray
{
    StructWithArray()
        : adaptedAry_(ary_)
    {}

    double dummy_; // see https://stackoverflow.com/questions/19823413/spirit-qi-attribute-propagation-issue-with-single-member-struct
    std::array<double, 6> ary_;
    AdaptedArrayType adaptedAry_;
};

BOOST_FUSION_ADAPT_STRUCT(
    StructWithArray
    ,
    (double, dummy_)
    (AdaptedArrayType, adaptedAry_)
    )

template <typename Iterator, typename Skipper>
struct StructWithArrayParser
    : qi::grammar<Iterator, StructWithArray(), Skipper>
{
    StructWithArrayParser() : StructWithArrayParser::base_type(start)
    {
        using qi::double_;

        arrayLine %= double_ > double_ > double_ > double_ > double_ > double_;
        start %= double_ > arrayLine;
    }

    qi::rule<Iterator, AdaptedArrayType(), Skipper> arrayLine;
    qi::rule<Iterator, StructWithArray(), Skipper> start;
};

int main() {
    std::string arrayStr = "0 1 2 3 4 5 6";
    std::string::const_iterator it = arrayStr.begin();
    std::string::const_iterator endIt = arrayStr.end();
    StructWithArrayParser<std::string::const_iterator, ascii::space_type> grammar;
    StructWithArray structWithArray;
    bool ret = phrase_parse(it, endIt, grammar, ascii::space, structWithArray);
    return 0;
}

person wonko realtime    schedule 23.12.2015    source источник


Ответы (1)


Вы путешествуете :) Вы, кажется, достигли варп-скорости с Духом в мгновение ока.

ОТРЕДАКТИРОВАНО После более внимательного прочтения вопроса я заметил, что вы просите более короткий и менее навязчивый способ.

Я не знаю ненавязчивого способа исправить это, но вы можете использовать boost::array, если вы специализируетесь на этом is_container.

Это довольно ненавязчиво, но все же меняет ваши типы.

Жить на Coliru

#include <boost/fusion/include/tuple.hpp>
#include <boost/fusion/adapted/boost_array.hpp>
#include <boost/spirit/include/qi.hpp>
#include <string>

namespace boost { namespace spirit { namespace traits {
    template <typename T, size_t N>
        struct is_container<boost::array<T, N>, void> : mpl::false_ { };
} } }

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

struct StructWithArray
{
    double dummy_; // see http://stackoverflow.com/questions/19823413/spirit-qi-attribute-propagation-issue-with-single-member-struct
    boost::array<double, 6> ary_;
};

BOOST_FUSION_ADAPT_STRUCT(StructWithArray, dummy_, ary_)

template <typename Iterator, typename Skipper>
struct StructWithArrayParser
    : qi::grammar<Iterator, StructWithArray(), Skipper>
{
    StructWithArrayParser() : StructWithArrayParser::base_type(start)
    {
        using qi::double_;

        arrayLine = double_ > double_ > double_ > double_ > double_ > double_;
        start     = double_ > arrayLine;
    }

  private:
    qi::rule<Iterator, boost::array<double, 6>(), Skipper> arrayLine;
    qi::rule<Iterator, StructWithArray(), Skipper> start;
};

int main() {
    std::string arrayStr = "0 1 2 3 4 5 6";
    using It = std::string::const_iterator;
    It it = arrayStr.begin(), endIt = arrayStr.end();
    StructWithArrayParser<It, ascii::space_type> grammar;

    StructWithArray structWithArray;
    bool ret = phrase_parse(it, endIt, grammar, ascii::space, structWithArray);
    std::cout << std::boolalpha << ret << "\n";

    for (double v : structWithArray.ary_)
        std::cout << v << " ";
}

Отпечатки:

true
1 2 3 4 5 6 
person sehe    schedule 23.12.2015
comment
После тестирования всех перестановок {g++,clang++} -std={c++03,c++11,c++14} с повышением 1.58,59,60 я обнаружил, что неправильно понял вопрос. Глядя в ближайшее время - person sehe; 23.12.2015
comment
Обновлен ответ с лучшим обходным путем, который я мог (легко) достичь. Мне кажется, вы могли бы отработать это, чтобы имитировать то же самое с std::array, но это не готово. - person sehe; 23.12.2015
comment
Фантастический обходной путь :) Именно то, на что я надеялся. Я могу счастливо жить с boost::array на данный момент, но внесу изменения, если у меня будет время, чтобы заставить его работать с std::array. Также здорово, что ваше решение указало мне на BOOST_PP_VARIADICS; так проще. - person wonko realtime; 24.12.2015
comment
Умно, с небольшим изменением это работает и для Spirit X3. Духу лучше знать, что array не вместилище. Жаль, что этот обходной путь не работает для std::array (потому что какая-то попытка Spirit переместить массив). /usr/include/boost/spirit/home/x3/support/traits/move_to.hpp:54:18: fatal error: no viable overloaded '=' - person alfC; 24.09.2016