Адаптируйте класс, содержащий строковый член, как синтезированный атрибут
Я пытаюсь разобрать строку символов в атрибут пользовательского типа 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.
Если ничего не помогает, вы можете взять свой торт и съесть его, потому что преобразование / назначение атрибутов - это точки настройки в библиотеке.
- Распространение и совместимость атрибутов
- Сохранить проанализированное значение атрибута (Qi)
- Хранить проанализированные значения атрибута в контейнере (Qi)
- ищите эти черты в ответах на SO для хороших примеров