2013-02-25 2 views
5

В статье Boost Phoenix «Трансформирование дерева выражений», here, набор специализаций настраиваемого класса invert_actions используется для инвертирования двоичных арифметических выражений. Например, a+b становится a-b; a*b становится a/b; и наоборот для обоих.Преобразование дерева выражений C++ Phoenix

Это связано с рекурсивным обходом дерева выражений, однако этот обход прекращается, когда встречается выражение, в котором используется оператор, явно не обработанный. Например, _1+_2-_3 станет _1-_2+_3, но _1+_1&_2 останется как есть (нет обработчика для &). let(_a = 1, _b = 2) [ _a+_b ] также останется без изменений.

Я думал, что это было сделано в соответствии с этой статьей, но, глядя на тесты, перечисленные в конце, я вижу, что ожидается, что if_(_1 * _4)[_2 - _3] изменится; с кодом (here), я нахожу, что это не так.

Каким образом можно определить общее генерирующее дерево выражений Boost Phoenix, которое применяется к всем набора явно перечисленных (n-арных) операторов; оставив остальных без изменений?

Некоторый код может быть полезен. Мне нужен следующий код C++ 11 (авто) для вывода 0, а не 2; без, явно обрабатывая & или любой другой оператор/оператор.

#include <iostream> 
#include <boost/phoenix.hpp> 
#include <boost/proto/proto.hpp> 

using namespace boost; 
using namespace proto; 
using namespace phoenix; 
using namespace arg_names; 

struct invrt { 
    template <typename Rule> struct when : proto::_ {}; 
}; 

template <> 
struct invrt::when<rule::plus> 
    : proto::call< 
    proto::functional::make_expr<proto::tag::minus>(
     evaluator(_left, _context), evaluator(_right, _context) 
    ) 
    > 
{}; 

int main(int argc, char *argv[]) 
{ 
    auto f = phoenix::eval(_1+_1&_2 , make_context(make_env(), invrt())); 
    std::cout << f(1,2) << std::endl; // Alas 2 instead of 0 
    return 0; 
} 

ответ

2

Это, как вы делаете это с прямой Proto:

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

struct invrt: 
    proto::or_< 
    proto::when< 
     // Turn plus nodes into minus 
     proto::plus<proto::_, proto::_>, 
     proto::functional::make_expr<proto::tag::minus>(
     invrt(proto::_left), invrt(proto::_right) 
    ) 
    >, 
    proto::otherwise< 
     // This recurses on children, transforming them with invrt 
     proto::nary_expr<proto::_, proto::vararg<invrt> > 
    > 
    > 
{}; 

int main(int argc, char *argv[]) 
{ 
    auto f = invrt()(_1+_1&_2); 
    proto::display_expr(f); 
    std::cout << f(1,2) << std::endl; 
    return 0; 
} 

Феникс слоистый кучу материала поверх Proto. Я не знаю семантики pheonix::eval или почему то, что вы пробовали, не работает. Возможно, кто-то знающий Феникс будет звонить в.

==== ==== EDIT

я понял, проблема с примером Phoenix. Это не рекурсия для случая, не связанного с плюсом. Ваш код должен выглядеть следующим образом:

#include <iostream> 
#include <boost/phoenix.hpp> 
#include <boost/proto/proto.hpp> 

using namespace boost; 
using namespace proto; 
using namespace phoenix; 
using namespace arg_names; 

struct invrt { 
    template <typename Rule> 
    struct when : 
    // NOTE!!! recursively transform children and reassemble 
    nary_expr<_, vararg<proto::when<_, evaluator(_, _context)> > > 
    {}; 
}; 

template <> 
struct invrt::when<rule::plus> : 
    proto::call< 
    proto::functional::make_expr<proto::tag::minus>(
     evaluator(_left, _context), evaluator(_right, _context) 
    ) 
    > 
{}; 

int main() 
{ 
    auto f = phoenix::eval(_1+_1&_2 , make_context(make_env(), invrt())); 
    display_expr(f); 
    std::cout << f(1,2) << std::endl; // Prints 0. Huzzah! 
} 

Считаете ли вы, что проще или сложнее, чем прямое прото решение для вас, чтобы решить.

+0

Спасибо @ Eric Niebler, это действительно фантастика - 2 решения очень щедры. Мне нравится использование первого прото, но второе использование шаблонных специализаций делает его красиво модульным; скажем, если бы я хотел добавить случай для правила :: делить снова. – user2023370

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

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