2010-03-19 10 views
5

al momento sono davvero interessato ai modelli di espressione e voglio codificare una libreria per scrivere e differenziare le funzioni matematiche con una sintassi in stile lambda. Al momento, sono in grado di scrivere (_x * _x)(2); e ottenere il risultato corretto 4. Ma mi piacerebbe davvero fare qualcosa come MathFunction f = _x * _x; f(2);, ma non ho alcuna idea su come affrontare i modelli di espressioni ricorsive sul lato destro . È possibile raggiungere questo obiettivo senza utilizzare la parola chiave 'auto' invece di MathFunction o dover rendere l'operatore() virtuale?Memorizzazione dei funtori modello di espressione

Grazie per il vostro aiuto!

risposta

0

Dato che sono un principiante di questo sito, ho trovato this non prima di aver inviato questa domanda. Grazie per le tue risposte, ma questo è quello che stavo davvero cercando.

1

Bene, Boost già supporta già questa funzionalità, quindi potresti voler dare un'occhiata a come l'hanno fatto.

I seguenti link sono stati davvero utili quando stavo imparando:
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

Il secondo collegamento è il mio preferito!

Tutto il meglio.

+1

Grazie per questa risposta e i collegamenti! Ho già scansionato la documentazione di Boost.Lambda per una soluzione al mio problema, ma non ho trovato una riga in cui quelle funzioni lambda sono effettivamente "memorizzate", vengono sempre utilizzate in linea. Al momento, utilizzo l'approccio "Modelli C++ - La guida definitiva" per i modelli di espressione. – fhenneke

+1

Eccezione non scoperta, stavo suggerendo di guardare il codice sorgente. Hai già guardato? – 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

Il distruttore 'MathFuncBase' dovrebbe essere virtuale per il tuo caso d'uso. Altrimenti quando 'shared_ptr' esce dallo scope avrà un comportamento indefinito. Il distruttore virtuale –

+0

è buono. Ma nel caso di 'shared_ptr' non è necessario. Controllare questo. –

+0

Immagino che intendevi fornire un riferimento che si è perso da qualche parte ... comunque, con 'shared_ptr' puoi fornire il tuo deleter come parametro al costruttore, ma nel blocco di codice sopra non lo stavi fornendo.Se non si fornisce il secondo argomento al costruttore 'shared_ptr', in distruzione chiamerà' delete' sul tipo del puntatore memorizzato ('MathFuncBase'). In questo caso particolare, l'UB molto probabilmente non avrebbe alcun effetto (negativo) (né la base né gli oggetti derivati ​​contengono alcun membro o eseguirà alcuna inizializzazione o distruzione) ma è comunque UB. –

0

Dubito che ciò sia possibile senza una funzione virtuale. È necessario eseguire la cancellazione dei caratteri poiché non è possibile utilizzare auto e simili. Ma successivamente in tale ambito, dal momento che si chiama una funzione sul tipo di oggetto cancellato, è necessario il supporto di runtime per richiamare una funzione sull'oggetto classe derivata.

Sospetto che senza auto non sia possibile.

1

In realtà non penso che ci sia un modo semplice per memorizzarli. Se volessi creare un'istanza denominata di espressione boost :: lambda, vorrei assegnare il risultato, per esempio, int e quindi copiare il nome del tipo di necessaria dal messaggio di errore del compilatore:

#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 nella vita reale è più probabile che le memorizziate in un tipo, cioè tipo cancellazioni, come 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); 
} 
Problemi correlati