2013-03-05 8 views
5

Wie kann ich auch Funktionskörper in eine Transformation eines Boost Phoenix-Ausdrucks aufnehmen?Transformieren von Funktionskörpern in Boost Phoenix Expressions

Zum Beispiel habe ich auf dem faulen Funktionen Abschnitt der Boost Phoenix Starter Kit gebaut und erstellt eine faule Zusatzfunktion:

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; 

bereite ich dann ein einfache Plus-zu-Minus-Transformation von einem previous question, hier gezeigt :

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> > 
    > 
    > 
{}; 

wenn ich jedoch einen umgekehrten Phoenix lambda Ausdruck anwenden, mit my_add, auf ihre Argumente, wie unten dargestellt, so scheint es, die beabsichtigte Inversion nicht erreicht worden ist. Gibt es eine empfohlene Möglichkeit, Funktionsaufrufe in Phoenix zu implementieren, die solche Transformationen erleichtern können?

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; 
} 

Antwort

3

Die Antwort ist wirklich sehr einfach und Sie werden sich selbst treten. Die Ausdruckstransformation, die Sie geschrieben haben, weiß, wie man einen Knoten Knoten in einen Knoten umwandelt. Aber es gibt keinen Plus-Knoten in dem Ausdruck, den Sie ihm übergeben. Schau nochmal:

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

Wo ist der Plusknoten? Für Proto (und für Phoenix) ist my_add undurchsichtig. Sie wissen nicht, dass da drinnen noch etwas hinzukommt. Wie konnten sie?

==== ==== EDIT

Betrachten Sie diese stattdessen, die tut, was Sie beabsichtigen:

#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! 
} 
+0

Thankyou. Ich hatte geahnt, dass dies der richtige Weg war, aber ich wollte etwas Beruhigung, bevor ich auf die Idee kam. – user2023370

+0

p.s. Ich denke, der "Let" -Körper könnte auch '_1 + _2' sein. – user2023370

+0

I/Think/Sie werden feststellen, dass Sie in komplizierteren Kontexten einen neuen Bereich für Ihre Funktionskörper erstellen müssen; daher das "Let". Zumindest erinnere ich mich, dass ich diese Lektion auf die harte Tour gelernt habe, aber für das Leben von mir kann ich mich nicht mehr erinnern, warum. :-P –