Преобразование тел функций в выражениях Boost Phoenix

Как я могу также включить функциональные тела в преобразование выражения Boost Phoenix?

Например, я построил раздел «Ленивые функции» Стартовый набор Boost Phoenix, и создал функцию отложенного добавления:

struct my_lazy_add_impl {
typedef int result_type;
template <typename T>
T operator()(T x, T y) const { return x+y; }
};
phoenix::function<my_lazy_add_impl> my_add;

Затем я готовлю простое преобразование плюс-минус из предыдущий вопрос, показано здесь:

struct invrt:
proto::or_<
proto::when<
proto::plus<proto::_, proto::_>,
proto::functional::make_expr<proto::tag::minus>(
invrt(proto::_left), invrt(proto::_right)
)
>,
proto::otherwise<
proto::nary_expr<proto::_, proto::vararg<invrt> >
>
>
{};

Тем не менее, когда я применяю перевернутый Феникс lambda выражение, используя my_addПо его аргументам, как показано ниже, кажется, что предполагаемая инверсия не была достигнута. Есть ли рекомендуемый способ реализации вызовов функций в Phoenix, который может облегчить такие преобразования?

int main(int argc, char *argv[])
{
auto f =         phoenix::lambda(_a = 0)[my_add(_1,_2)];
auto g = invrt()(phoenix::lambda(_a = 0)[my_add(_1,_2)]);
std::cout << f()(1,2) << std::endl; // 3
std::cout << g()(1,2) << std::endl; // 3 again; alas not -1
return 0;
}

5

Решение

Ответ на самом деле очень прост, и вы собираетесь ударить себя. Преобразование выражения, которое вы написали, знает, как преобразовать плюс узел в вычитание узел. Но в выражении, которое вы ему передаете, нет плюсового узла. Посмотри снова:

auto g = invrt()(phoenix::lambda(_a = 0)[my_add(_1,_2)]);

Где плюсовой узел? Прото (и Фениксу), my_add непрозрачный Они не знают, что там происходит дополнение. Как они могли?

==== ==== EDIT

Рассмотрим это вместо этого, что делает то, что вы намерены:

#include <iostream>
#include <boost/phoenix.hpp>
#include <boost/proto/proto.hpp>
namespace proto = boost::proto;
namespace phoenix = boost::phoenix;
using namespace phoenix::arg_names;
using namespace phoenix::local_names;

auto const my_add = phoenix::let(_a = _1, _b = _2)[_a + _b];

struct invrt:
proto::or_<
proto::when<
proto::plus<proto::_, proto::_>,
proto::functional::make_expr<proto::tag::minus>(
invrt(proto::_left), invrt(proto::_right)
)
>,
proto::otherwise<
proto::nary_expr<proto::_, proto::vararg<invrt> >
>
>
{};

int main()
{
auto f =         phoenix::lambda(_a = 0)[my_add(_1,_2)];
auto g = invrt()(phoenix::lambda(_a = 0)[my_add(_1,_2)]);

std::cout << f()(1,2) << std::endl; // 3
std::cout << g()(1,2) << std::endl; // -1, w00t!
}
3

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

Других решений пока нет …