Адаптируйте класс, содержащий строковый член, как синтезированный атрибут

Я пытаюсь разобрать строку символов в атрибут пользовательского типа symbol, который содержит std::string член. Я думал, что мог бы использовать BOOST_FUSION_ADAPT_STRUCT здесь, но это не работает.

Если я объявлю правило как rule<It, std::string(), space_type> оно работает. Если я определю это как rule<It, symbol(), space_type> происходит сбой с ошибкой "нет имени типа value_type в symbol". Я думаю, что Spirit пытается добавить значение символ за символом к ​​атрибуту, который терпит неудачу, как и ожидалось. Но разве нет способа сделать это без добавления дополнительного промежуточного правила, которое фиксирует std::string атрибут?

Вот полный MWE:

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>

struct symbol 
{ 
    std::string repr; 
};

BOOST_FUSION_ADAPT_STRUCT(symbol, (std::string, repr))

namespace qi = boost::spirit::qi;

template <typename Iterator>
struct test_grammar : qi::grammar<Iterator, symbol(), qi::ascii::space_type> {
    test_grammar() : test_grammar::base_type{start} {
        start = qi::lexeme[+qi::char_("a-z")];
    }

    qi::rule<Iterator, symbol(), qi::ascii::space_type> start;
};

#include <iostream>

auto main() -> int {
    test_grammar<std::string::iterator> grammar{};
    auto input = std::string{"test"};
    auto output = symbol{};
    auto e = end(input);
    if (qi::phrase_parse(begin(input), e, grammar, qi::ascii::space, output))
        std::cout << output.repr;
}

1 ответ

Решение

Как вы видели из связанного дуэта, вы можете обойти это с хорошо расположенным qi::eps,

    start = qi::eps >> qi::lexeme[+qi::char_("a-z")];

Посмотри это в прямом эфире на Колиру

Однако бывают случаи, когда qi::eps не сохраняет (Постараюсь найти ссылки позже). Поэтому я предпочел "старомодный подход" для совместимости атрибутов:

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

struct symbol 
{ 
    std::string repr; 

    symbol(std::string repr = std::string()) : repr(std::move(repr)) {}
};

namespace qi = boost::spirit::qi;

template <typename Iterator>
struct test_grammar : qi::grammar<Iterator, symbol(), qi::ascii::space_type> {
    test_grammar() : test_grammar::base_type(start) {
        using namespace qi;

        start = as_string[ lexeme[ +char_("a-z") ] ];
    }

    qi::rule<Iterator, symbol(), qi::ascii::space_type> start;
};

#include <iostream>

auto main() -> int {
    test_grammar<std::string::iterator> grammar{};
    auto input = std::string{"test"};
    auto output = symbol{};
    auto e = end(input);
    if (qi::phrase_parse(begin(input), e, grammar, qi::ascii::space, output))
        std::cout << output.repr;
}

Это также, вероятно, немного легче для компилятора. Посмотрите это в прямом эфире на Coliru.

Если ничего не помогает, вы можете взять свой торт и съесть его, потому что преобразование / назначение атрибутов - это точки настройки в библиотеке.

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