Boost Spirit Karma повторяет один и тот же вывод для каждой записи в векторе

Начиная с тривиальной проблемы, я решил использовать boost::spirit::karma превратить это во что-то более хитрое. У нас есть карта, которая отображает записи enum class в vectorс ints, я хотел бы произвести вывод вида

Foo имеет 3 записи:

Фу имеет 1

Фу имеет 5

Фу имеет 7

...

если есть запись {Foo, {1, 5, 7}} в данных.

Формат данных на самом деле не так важен, но если бы ключ карты был stringс или intс, можно использовать karma::lit снова вывести сохраненный атрибут. Однако это невозможно, и правило использует атрибут, что делает невозможным его повторное использование.

Мне удалось извлечь размер вектора с полным взломом, но я не могу получить имя Foo повторяться

#include <string>
#include <type_traits>
#include <vector>

#define BOOST_SPIRIT_USE_PHOENIX_V3

#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>

#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/karma_symbols.hpp>

#include <boost/phoenix/bind/bind_member_variable.hpp>

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

enum class TableName {
    Foo,
    Bar
};

using Map = std::map<TableName, std::vector<int>>;

template<typename OutputIterator>
struct TestGrammar : boost::spirit::karma::grammar<OutputIterator, Map()>
{
    TestGrammar() : TestGrammar::base_type(testRule)
    {
        using boost::spirit::karma::duplicate;
        using boost::spirit::karma::int_;
        using boost::spirit::karma::lit;
        using boost::spirit::karma::_a;
        using boost::spirit::karma::_1;
        using boost::spirit::karma::_val;
        using boost::spirit::karma::skip;
        using boost::phoenix::ref;
        using boost::phoenix::size;

        tableNameSymbols.add
            (TableName::Foo, "Foo")
            (TableName::Bar, "Bar")
        ;

        tableNameRule %= tableNameSymbols;


        // Using _a instead of size_ or sym_ does not work... why?
        pairRule %= tableNameRule[ref(sym_) = _1] <<
            duplicate[
                skip[*int_][ref(size_) = size(_1)] <<
                    lit(" has ") << lit(ref(size_)) << " entries:\n" <<
                    *(lit('\t') << /* tableNameRule[_1 = ref(sym_)] */ lit("IT") << lit(" has ") << int_ << lit('\n'))
                ];

        testRule = *(pairRule << lit('\n'));
    }

    boost::spirit::karma::symbols<TableName, const char *> tableNameSymbols;
    boost::spirit::karma::rule<OutputIterator, TableName()> tableNameRule;
    boost::spirit::karma::rule<OutputIterator, std::pair<TableName, std::vector<int>>()> pairRule;
    boost::spirit::karma::rule<OutputIterator, Map()> testRule;
    private:
    std::size_t size_;
    TableName sym_;
};

int main()
{
    using namespace boost::spirit::karma;

    Map map = {
        {TableName::Foo, {1, 5, 7}},
        {TableName::Bar, {2}}
    };

    std::string output;
    std::back_insert_iterator<std::string> sink(output);

    /*
     * The following outputs

        Foo has 3 entries:
            IT has 1
            IT has 5
            IT has 7

        Bar has 1 entries:
            IT has 2

        It should output:

        Foo has 3 entries:
            Foo has 1
            Foo has 5
            Foo has 7

        Bar has 1 entries:
            Bar has 2
    */

    bool r = generate(
            sink,
            TestGrammar<std::decay<decltype(sink)>::type>(),
            map
        );

    std::cout << output;

    return r == false;
}

0 ответов

Другие вопросы по тегам