In dem Boost-Phoenix-Artikel "Transforming the Expression Tree" here, ein Satz von Spezialisierungen einer benutzerdefinierten invert_actions
-Klasse, werden binäre arithmetische Ausdrücke invertiert. Zum Beispiel wird a-b
; a*b
wird a/b
; und umgekehrt für beide.Transformieren eines Boost C++ - Phoenix-Ausdrucksbaums
Hierbei handelt es sich um eine rekursive Traversierung des Ausdrucksbaums. Diese Traversierung wird jedoch beendet, wenn ein Ausdruck gefunden wird, der einen Operator betrifft, der nicht explizit behandelt wird. Zum Beispiel wird _1+_2-_3
_1-_2+_3
, aber _1+_1&_2
bleibt so wie es ist (es gibt keinen Handler für &
). let(_a = 1, _b = 2) [ _a+_b ]
wird auch unverändert bleiben.
Ich hatte gedacht, dies war wie in dem Artikel vorgesehen, aber mit Blick auf die Tests am Ende aufgeführt, sehe ich, dass if_(_1 * _4)[_2 - _3]
erwartet wird, zu ändern; mit dem Code geliefert (here), finde ich, dass es nicht.
Wie kann ich dann eine generische Boost Phoenix Expression Tree Transformation definieren, die auf einer Reihe von explizit aufgeführten (n -ary) Operatoren gilt; die anderen unverändert lassen?
Einige Codes können nützlich sein. Ich möchte den folgenden C++ 11-Code (automatisch) ausgeben 0
, und nicht 2
; ohne, das ausdrücklich die &
oder irgendeinen anderen Operator/eine Anweisung behandelt.
#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;
}
Dank @Eric Niebler, das ist wirklich fantastisch - 2 Lösungen sind sehr großzügig. Ich mag die erste Verwendung von Proto, aber die Verwendung von Template-Spezialisierungen durch die zweite macht es schön modular; sagen, wenn ich den Fall für Regel :: dividiert wieder hinzufügen wollte. – user2023370