2

Я пытаюсь создать правило, которое возвращает function<char(char const *)>, созданное путем выражения выражения Феникса. НАПРИМЕР,Построение правила qi :: с атрибутом функции

start = int_[_val = xxx]; 
rule<Iterator, function<char(char const *)> start; 

Что должно xxx быть так, что разбор строки "5" должен дать мне функцию, которая дает мне пятый характер его ввода? Я пробовал такие вещи, как lambda(_a = arg1)[arg1[_a]](_1), но я не смог наброситься на магическую формулу.

Другими словами, я хотел бы атрибут, чтобы снискать arg2[arg1] на значения анализируемой Int

Очень благодарен за любые предложения. Обратите внимание, что я на VC2008, поэтому C++ 11 lambdas недоступен.

Майк

ответ

2

После исправления этой декларации правила:

typedef boost::function<char(char const*)> Func; 
qi::rule<Iterator, Func()> start; 

он работал: Live On Coliru (C++ 03).

UPDATE:

Почему я в конечном итоге с такой сложной штуковине?

qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1) 

Хорошо. Позвольте мне рассказать вам о радости комплексообразования функционального состава с ленивым вычислениям (в C++ шаблон мета-программирования, который имеет эти сюрпризы со ссылкой/значение семантики): Не сделать следующее:

qi::_val = px::lambda(_a = qi::_1) [arg1[_a]] // UB!!! DON'T DO THIS 

В зависимости от компилятор, уровень оптимизации, это может * появляется для работы. Но он вызывает неопределенное поведение [1]. Проблема заключается в том, что qi::_1 будет храниться как ссылка на атрибут, выставленный выражением парсера qi::int_. Однако эта ссылка, после того как срок жизни контекста синтаксического анализа завершился, является обманутой ссылкой.

Итак, оценивая косвенные функции через недопустимую ссылку. Чтобы избежать этого, следует сказать (Live On Coliru):

qi::_val = px::lambda(_a = px::val(qi::_1)) [arg1[_a]] 

или даже (если вам нравится неясного код):

qi::_val = px::lambda(_a = +qi::_1) [arg1[_a]] 

Или, вы знаете, вы можете придерживаться связанной вложенным лямбда, поскольку привязка по умолчанию к значению-семантике для qi::_1 (если вы не использовали обертки phx::cref/phx::ref).

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

Обратите внимание, что я бы не рекомендовал этот код стиля.Программирование более высокого порядка с Phoenix достаточно сложно, не составив их из ленивых актеров в некотором встроенном шаблоне выражения DSL: qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1). 'Nuff said?


#define BOOST_SPIRIT_USE_PHOENIX_V3 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 
#include <boost/function.hpp> 

namespace qi = boost::spirit::qi; 
namespace px = boost::phoenix; 

typedef boost::function<char(char const*)> Func; 

int main() 
{ 
    typedef std::string::const_iterator Iterator; 
    using namespace boost::phoenix::arg_names; 

    qi::rule<Iterator, Func()> start; 

    start = qi::int_ 
      [ qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1) ]; 
    // or: [ qi::_val = px::lambda(_a = px::val(qi::_1))[arg1[_a]] ]; 

    static char const* inputs[] = { "0", "1", "2", "3", "4", 0 }; 

    for (char const* const* it = inputs; *it; ++it) 
    { 
     std::string const input(*it); 
     Iterator f(input.begin()), l(input.end()); 

     Func function; 
     bool ok = qi::parse(f, l, start, function); 

     if (ok) 
      std::cout << "Parse resulted in function() -> character " 
       << function("Hello") << "; " 
       << function("World") << "\n"; 
     else 
      std::cout << "Parse failed\n"; 

     if (f != l) 
      std::cout << "Remaining unparsed: '" << std::string(f, l) << "'\n"; 
    } 
} 

Печать

Parse resulted in function() -> character H; W 
Parse resulted in function() -> character e; o 
Parse resulted in function() -> character l; r 
Parse resulted in function() -> character l; l 
Parse resulted in function() -> character o; d 

[1] (MSVC2013 появился сбой, GCC может появиться работать в -O3, но в -O0 ошибку сегментации)

+0

Спасибо, что ответили, но, к сожалению, я не думаю, что это разрешает мой вопрос. Если я что-то не хватает, приведенный выше код, похоже, игнорирует целое число, которое было проанализировано, и это то, что я пытался включить. Я хочу, чтобы вход был «2», а 'output (« Hello »)' должен быть 'e'. Вы знаете, как я могу это сделать? – user2913094

+0

@ пользователь2913094 Wokay. Я обновил образец, чтобы быть более полным. Обратите внимание, что я бы не рекомендовал этот стиль кода. Программирование более высокого порядка с Phoenix достаточно сложно, не составив их из ленивых участников в каком-то встроенном шаблоне выражения DSL: 'qi :: _ val = px :: bind (px :: lambda [arg1 [arg2]], px :: lambda [arg1], qi :: _ 1) '. *** Нафф сказал ***? – sehe

+1

Похоже, хороший совет. Альтернативы (например, создание класса функтора и вообще избегание лямбда) немного неуклюжи, но, по крайней мере, они понятны. Благодаря! – user2913094

 Смежные вопросы

  • Нет связанных вопросов^_^