Построение qi :: rule с атрибутом функции

Я пытаюсь создать правило, которое возвращает function<char(char const *)> построенный путем карри выражения Феникса. Например.,

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 лямбды не доступны.

Майк

2

Решение

После исправления этого правила:

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

это сработало: Жить на Колиру (C ++ 03).

ОБНОВИТЬ:

Почему у меня получилось такое сложное устройство?

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_ выражение парсера. Однако эта ссылка после окончания срока действия контекста синтаксического анализатора является висячей ссылкой.

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

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), ‘Достаточно?


#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 и т. Д.)

2

Другие решения


По вопросам рекламы [email protected]