Ausdrücke zur Laufzeit berechnen und als Objekte weitergeben
-
folgendes Szenario: Ich habe eine Klasse, die über einen (sehr) langen Stream von Daten läuft. Bei jedem Schritt wird ein Haufen Membervariablen der Klasse mit Daten aus dem Stream gefüllt und in Abhängigkeit dieser Variablen werden einige verschiedene Aktionen ausgeführt. Ich habe überlegt, ob es eventuell möglich wäre, Objekte zu erstellen, die einen bestimmten Ausdruck präsentieren, Referenzen auf einige Variablen haben und bei Bedarf mit dem aktuellen Wert der Variablen ausgewertet werden können, beispielsweise
class Foo; class Bar; Foo operator% (double, Foo); Bar operator+ (Foo, int); struct Holder { int a; double b; Foo c; }; int main() { Holder h; ExpressionObject exp("(h.c % h.a) + h.b ", h.c, h.a, h.b); /* mach was mit bar ...*/ Bar bar = exp.evaluate(); //ergibt den aktuellen Wert von (h.c % h.a) + h.b /*...*/ Bar bar2 = exp.evaluate(); //ergibt den aktuellen Wert von (h.c % h.a) + h.b }Gibt es schon Dinge, die in die Richtung gehen? Man könnte sicherlich für jeden Ausdruck von Hand ein Funktionsobjekt schreiben, das wollte ich mir aber sparen (es wären einige hundert) und trotzdem Objekte wie im Beispiel haben, um sie in der Applikation herumzureichen.
-
Du hast dabei ja schon das Problem das das Programm zur Laufzeit gar nicht weiß das Holder die Membervariablen a, b und c hat. Wenn würde das wohl eher im Stile von printf funktionieren. Also mit Platzhaltern die die Argumente referenzieren.
-
Fellhuhn schrieb:
Du hast dabei ja schon das Problem das das Programm zur Laufzeit gar nicht weiß das Holder die Membervariablen a, b und c hat.
Braucht es auch nicht wissen, wenn exp Referenzen auf die Variablen behaelt.
-
Was ich meine ist das aus dem String "(h.c % h.a) + h.b " kein Rückschluss auf die angehängten Variablen gegeben werden kann. Eher wäre da sowas sinnvoll wie:
... exp("($1 % $2) + $3 ", h.c, h.a, h.b);Weil zwischen "h.c" und h.c besteht nur zur Kompilierzeit ein Zusammenhang.
-
klar, dass das so mit dem String nicht ganz funktioniert ist mir bewusst. Ich hab mir schon einige Gedanken gemacht,dass man das evtl mit Templates regeln koennte:
template<typename Result, typename Left, typename Right> class add_expr { Left const& l; Right const& r; public: typedef Result result_t; add(Left const& l, Right const& r) : l(l), r(r) {} result_t eval() { return l+r; } }; template <typename Result, typename Left, typename Right> add_expr<Result, Left, Right> add(Left const& l, Right const& r) { return add_expr(l,r); }int main() {
int i;
double d;
add_expr<int, int, double> e = add<int>(i,d);
}[/cpp]Das ist nur ein Anfang, um kompliziertere Ausdruecke zusammenzubauen muss das Funktionstemplate unterscheiden, ob einer der Parameter eine Variable oder ein anderer Ausdruck ist, entsprechend muessen die zurueckgegebenen Typen unterschiedlich sein, um das richtige Auswerten des Ausdrucks zu managen...
-
Grundsätzlich möglich ist sowas auch mit Mitteln der Standardbibliothek (TR1). Die Probleme sind die gleichen wie bei Deiner Lösung, aber vielleicht hilft die Idee in irgendeiner Weise weiter. Evtl. kann man das ganze so auf Helperfunktionen beschränken und die Klasse *_expr einsparen.
int a, b; std::tr1::function< int () > f = std::tr1::bind( std::plus< int >(), std::tr1::ref(a), std::tr1::ref(b) ); a = 1; b = 1; std::cout << f() << std::endl; a = 12; b = 3; std::cout << f() << std::endl; return f;
-
muss ich mir mal anschauen wie weit ich damit kommen kann, z.B. ob ich damit auch gemischte Operatoren wie die beiden in meinem ersten Beispiel hinbekomme. Ich hatte schon wilde Phantasien, wie man massive Operatorueberladungen frei nach boost::spirit implementieren kann um etwa sowas wie das Folgende hinzubekommen:
bool ask(); int main() { int a, b, c; double d, e, f; Expression<bool> e = ((expr(a) < b) && (expr(d) != e)) || (expr(c) < f) && !fun_expr(&ask)); /*...*/ bool b = e(); }Der Typ auf der rechten Seite des Gleicheitszeichens waere dann in etwa ein
logic_and<logic_or<logic_and<less_expression<int,int>,uneq_expression<double, double> >,less_expression<int,double> >,logic_not<fun_expression<bool (*)()> > >
Die Funktionen, um sowas zusammenzubauen sollten relativ einfach machbar sein, wenn man den Ueberblick behaelt und fleissig tippt
-
Hallo Pumuckl,
da spricht nichts gegen. Das ist sogar durchaus üblich, auf diese Weise Ausdrucksbäume zu generieren. Ich habe gerade gestern aus reinem Jux einen kleinen Ausdrucksauswerter für Bool-Ausdrücke geschrieben, der genau das macht.