W artykule Boost Phoenix "Transformowanie drzewa wyrażeń", here, zestaw specjalizacji niestandardowej klasy invert_actions
, służą do odwracania binarnych wyrażeń arytmetycznych. Na przykład a+b
staje się a-b
; a*b
staje się a/b
; i vice versa dla obu.Przekształcanie drzewa stanu C++ Phoenix Expression
Dotyczy to rekursywnego przejścia drzewa wyrażeń - jednak to przejście zatrzymuje się, gdy napotkane zostanie wyrażenie z udziałem operatora, który nie jest jawnie obsługiwany. Na przykład _1+_2-_3
stanie się _1-_2+_3
, ale _1+_1&_2
pozostanie bez zmian (nie ma obsługi dla &
). let(_a = 1, _b = 2) [ _a+_b ]
również pozostanie niezmieniony.
Myślałem, że jest to zgodne z przeznaczeniem artykułu, ale patrząc na testy wymienione na końcu, widzę, że oczekuje się, że zmiana zostanie zmieniona na if_(_1 * _4)[_2 - _3]
; z dostarczonym kodem (here), stwierdzam, że tak nie jest.
W jaki sposób można zdefiniować ogólną transformację drzewa ekspresji w funkcji Wzmocnienie Phoenix, która ma zastosowanie do wszystkich zbioru wyraźnie wymienionych (n-ary) operatorów; pozostawiając pozostałe bez zmian?
Niektóre kody mogą być przydatne. Chciałbym następujący kod C++ 11 (auto) do wyjścia 0
, a nie 2
; bez jawnie obsługujących &
lub dowolnego innego operatora/instrukcji.
#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;
}
Dzięki @Eric Niebler, to naprawdę fantastyczne - 2 rozwiązania są bardzo hojne. Podoba mi się pierwsze użycie proto, ale drugie użycie szablonowych specjalizacji sprawia, że jest ładnie modułowy; powiedz, jeśli chcę dodać argumenty dotyczące reguły :: dzieli ponownie. – user2023370