2014-02-02 1 views
7

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

Если я объявляю правило как rule<It, std::string(), space_type>, он работает. Если я определяю его как rule<It, symbol(), space_type>, он терпит неудачу с ошибкой «no type name value_type in symbol». Я думаю, что Spirit пытается добавить значение character-for-character к атрибуту, который не соответствует ожидаемому. Но нет ли способа сделать эту работу, без, добавив дополнительное промежуточное правило, которое захватывает атрибут 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; 
} 
+5

Это известное ограничение/ошибка в Духе. Я считаю, что это происходит, когда вы адаптируете структуры, которые имеют один элемент, и этот элемент является «контейнером». Обычным обходным решением является 'start% = eps >> lexeme [+ char _ ('a', 'z')];', по-видимому, это заставляет атрибут правой стороны быть «tuple », и это отлично работает с вашим адаптированная структура. Я попытаюсь найти дубликат. – llonesmiz

+0

@cv_and_he Да, это [работает] (http://coliru.stacked-crooked.com/a/0634b0eb16d67e46) с этим обходным решением – P0W

+0

@cv_and_he Скопируйте это в ответ, чтобы я мог его принять. –

ответ

2

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

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

Посмотреть Live On Coliru

Однако, есть случаи, когда 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; 
} 

Это также, вероятно, немного легче на компилятор. См. Его Live on Coliru как есть.

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