2010-03-19 7 views
5

im Moment bin ich wirklich interessiert an Expression-Templates und möchte eine Bibliothek zum Schreiben und Differenzieren mathematischer Funktionen mit einer Lambda-Stil-Syntax zu kodieren. Im Moment kann ich (_x * _x)(2); schreiben und das richtige Ergebnis 4 bekommen. Aber ich würde gerne etwas wie MathFunction f = _x * _x; f(2); machen, aber ich habe keine Ideen, wie ich mit den rekursiven Ausdruckvorlagen auf der rechten Seite umgehen soll . Ist es möglich, dies zu erreichen, ohne das 'auto'-Schlüsselwort anstelle von MathFunction zu verwenden oder den Operator() virtuell zu machen?Expression-Template-Funktoren speichern

Danke für Ihre Hilfe!

Antwort

0

Da ich ein Neuling auf dieser Website bin, habe ich this nicht gefunden, bis ich diese Frage einreichte. Danke für deine Antworten, aber das ist es, wonach ich wirklich gesucht habe.

1

Nun, Boost unterstützt diese Funktionalität bereits, daher sollten Sie sich ansehen, wie sie das gemacht haben.

Die folgenden Links waren sehr hilfreich, wenn ich lernte:
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Expression-template
http://www.angelikalanger.com/Articles/Cuj/ExpressionTemplates/ExpressionTemplates.htm http://www.flipcode.com/archives/Faster_Vector_Math_Using_Templates.shtml

Der zweite Link ist mein persönlicher Favorit!

Alles Gute.

+1

Danke für diese Antwort und die Links! Ich habe die Boost.Lambda-Dokumentation bereits gescannt, um eine Lösung für mein Problem zu finden, aber ich habe keine Zeile gefunden, in der diese Lambda-Funktionen tatsächlich "gespeichert" sind, sie werden immer inline verwendet. Im Moment verwende ich den Ansatz "C++ - Vorlagen - Der eindeutige Leitfaden" für Expression-Vorlagen. – fhenneke

+1

Uncaught Ausnahme, ich schlug vor, dass Sie den Quellcode betrachten. Hast du schon gesucht? – batbrat

3

.

template<class T, class R> 
struct MathFuncBase 
{ 
    virtual R operator()(const T & v) = 0; 
    virtual ~MathFuncBase() {} 
}; 

tempate<class T, class R, class Func> 
struct MathFunc : MathFuncBase<T, R> 
{ 
    MathFunc(Func func) : func(func) {} 
    virtual R operator()(const T & v) { 
     return func(v);   
    } 
private: 
    Func func; 
}; 

tempate<class T, class R, class Func> 
boost::shared_ptr<MathFuncBase<T, R> > GetMathFunc(Func func) { 
    return boost::shared_ptr<MathFuncBase<T, R> >(new MathFunc<T, R, Func> (func)); 
} 

int main() { 
    boost::shared_ptr<MathFuncBase<int, int> > f = GetMathFunc<int,int> (_x * _x); 
    return (*f)(2); 
} 
+0

'MathFuncBase' Destruktor sollte für Ihren Anwendungsfall virtuell sein. Sonst, wenn der 'shared_ptr' den Gültigkeitsbereich verlässt, wird es undefiniertes Verhalten haben. –

+0

virtueller Destruktor ist gut. Aber im Fall von 'shared_ptr' wird es nicht benötigt. Überprüfen Sie dies. –

+0

Ich vermute, Sie wollten eine Referenz liefern, die irgendwo verloren ging ... trotzdem können Sie mit 'shared_ptr' einen eigenen Deleter als Parameter für den Konstruktor angeben, aber im obigen Codeblock haben Sie ihn nicht bereitgestellt.Wenn Sie dem Konstruktor 'shared_ptr' nicht das zweite Argument übergeben, ruft es bei der Zerstörung 'delete' für den Typ des gespeicherten Zeigers auf (' MathFuncBase'). In diesem speziellen Fall würde die UB höchstwahrscheinlich keinen (schlechten) Effekt haben (weder die Basis noch die abgeleiteten Objekte enthalten irgendwelche Mitglieder oder führen irgendeine Initialisierung oder Zerstörung durch), aber es ist dennoch UB. –

0

Ich bezweifle, dass dies ohne eine virtuelle Funktion möglich ist. Sie müssen Löschvorgang eingeben, da Sie und ähnliche nicht verwenden können. Aber später in diesem Gültigkeitsbereich, da Sie eine Funktion für das Typ-gelöschte Objekt aufrufen, benötigen Sie Laufzeitunterstützung, um eine Funktion für das abgeleitete Klassenobjekt aufzurufen.

Ich vermute, ohne auto können Sie es nicht tun.

1

Eigentlich glaube ich nicht, dass es eine einfache Möglichkeit gibt, sie zu speichern. Wenn ich eine benannte Instanz von boost :: Lambda-Ausdruck erstellen wollte, würde ich das Ergebnis zu, sagen wir, zuweisen int und dann den Namen des benötigten Typs kopieren aus der Fehlermeldung des Compilers:

#include <boost/lambda/lambda.hpp> 

int main() 
{ 
    using namespace boost::lambda; 
    //int x = _1 + _2; 
    boost::lambda::lambda_functor<boost::lambda::lambda_functor_base< 
    boost::lambda::arithmetic_action<boost::lambda::plus_action>, 
    boost::tuples::tuple<boost::lambda::lambda_functor<boost::lambda::placeholder<1> >, 
    boost::lambda::lambda_functor<boost::lambda::placeholder<2> >, 
    boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, 
    boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, 
    boost::tuples::null_type, boost::tuples::null_type> > > x = _1 + _2; 
} 

In Im wirklichen Leben ist es wahrscheinlicher, dass Sie sie in einem Typ speichern, der eine Löschung eingibt, wie boost::function.

#include <boost/lambda/lambda.hpp> 
#include <boost/function.hpp> 
int main() 
{ 
    using namespace boost::lambda; 
    boost::function<int(int, int)> x = _1 + _2; 
    return x(-1, 1); 
} 
Verwandte Themen