2012-10-25 15 views
6

Vorrei utilizzare GSL all'interno di una classe C++ senza dichiarare funzioni membro come static. Il motivo è perché non li conosco troppo bene e non sono sicuro della sicurezza dei thread. Da quello che ho letto, std::function potrebbe essere una soluzione, ma non sono sicuro di come usarlo.come evitare la funzione di membro statico quando si utilizza gsl con C++

La mia domanda si riduce a come posso rimuovere static nella dichiarazione di g?

#include<iostream> 
#include <functional> 
#include <stdlib.h> 
#include <gsl/gsl_math.h> 
#include <gsl/gsl_monte.h> 
#include <gsl/gsl_monte_plain.h> 
#include <gsl/gsl_monte_miser.h> 
#include <gsl/gsl_monte_vegas.h> 


using namespace std; 

class A { 
public: 
    static double g (double *k, size_t dim, void *params) 
    { 
    double A = 1.0/(M_PI * M_PI * M_PI); 
    return A/(1.0 - cos (k[0]) * cos (k[1]) * cos (k[2])); 
    } 
    double result() { 
    double res, err; 

    double xl[3] = { 0, 0, 0 }; 
    double xu[3] = { M_PI, M_PI, M_PI }; 

    const gsl_rng_type *T; 
    gsl_rng *r; 

    ////// the following 3 lines didn't work /////// 
    //function<double(A,double*, size_t, void*)> fg; 
    //fg = &A::g; 
    //gsl_monte_function G = { &fg, 3, 0 }; 
    gsl_monte_function G = { &g, 3, 0 }; 

    size_t calls = 500000; 

    gsl_rng_env_setup(); 

    T = gsl_rng_default; 
    r = gsl_rng_alloc (T); 

    { 
     gsl_monte_plain_state *s = gsl_monte_plain_alloc (3); 
     gsl_monte_plain_integrate (&G, xl, xu, 3, calls, r, s, &res, &err); 
     gsl_monte_plain_free (s); 
    } 

    gsl_rng_free (r); 
    return res; 
    } 
}; 

main() { 
    A a; 
    cout <<"gsl mc result is " << a.result() <<"\n"; 
} 

Update (1):

Ho provato a cambiare gsl_monte_function G = { &g, 3, 0 };-gsl_monte_function G = { bind(&A::g, this,_1,_2,_3), 3, 0 };, ma non ha funzionato

Update (2): Ho provato ad utilizzare assigning std::function to a member function ma didn' anche lavorare.

Update (3) alla fine ho scritto una funzione non membro:

double gmf (double *k, size_t dim, void *params) { 
    auto *mf = static_cast<A*>(params); 
    return abs(mf->g(k,dim,params)); 
    //return 1.0; 
}; 

Ha funzionato, ma è una soluzione disordinata perché avevo bisogno di scrivere una funzione di supporto. Con lambdas, function e bind, dovrebbe esserci un modo per avere tutto logico all'interno della classe.

+0

so che la mia risposta è arrivata piuttosto tardi, ma spero che la classe involucro può aiutare in futuro. Questo wrap è molto utile perché consente anche di integrare le funzioni lambda o di associare le funzioni a più di un parametro (se si desidera integrare f (x, a) = a x dove a è un parametro, ad esempio). –

risposta

7

Si può facilmente avvolgere le funzioni di membro utilizzando il seguente codice (che è una soluzione ben nota)

class gsl_function_pp : public gsl_function 
{ 
    public: 
    gsl_function_pp(std::function<double(double)> const& func) : _func(func){ 
     function=&gsl_function_pp::invoke; 
     params=this; 
    }  
    private: 
    std::function<double(double)> _func; 
    static double invoke(double x, void *params) { 
    return static_cast<gsl_function_pp*>(params)->_func(x); 
    } 
}; 

Quindi è possibile utilizzare std :: bind per avvolgere la funzione membro in uno std :: funzione. Esempio:

gsl_function_pp Fp(std::bind(&Class::member_function, &(*this), std::placeholders::_1)); 
gsl_function *F = static_cast<gsl_function*>(&Fp);  

Tuttavia, si deve essere consapevoli circa le riduzioni di prestazioni di std :: funzione prima del confezionamento funzioni membro all'interno di routine integrazione GSL. Vedi template vs std::function.Per evitare questo calo di prestazioni (che può o non può essere fondamentale per voi), si dovrebbe utilizzare i modelli come illustrato di seguito

template< typename F > 
    class gsl_function_pp : public gsl_function { 
    public: 
    gsl_function_pp(const F& func) : _func(func) { 
    function = &gsl_function_pp::invoke; 
    params=this; 
    } 
    private: 
    const F& _func; 
    static double invoke(double x, void *params) { 
    return static_cast<gsl_function_pp*>(params)->_func(x); 
    } 
}; 

In questo caso, per chiamare una funzione membro è necessario quanto segue

Class* ptr2 = this; 
auto ptr = [=](double x)->double{return ptr2->foo(x);}; 
gsl_function_pp<decltype(ptr)> Fp(ptr);  
gsl_function *F = static_cast<gsl_function*>(&Fp); 

PS: il collegamento template vs std::function spiega che il compilatore di solito ha un tempo di ottimizzazione dei modelli più semplice rispetto a std :: function (che è fondamentale per le prestazioni se il codice sta eseguendo pesanti calcoli numerici). Quindi anche la soluzione alternativa nel secondo esempio sembra più complessa, preferirei i template rispetto a std :: function.

+0

È una buona soluzione ma utilizza ancora funzioni membro statiche. comunque, lo contrassegno come risposta per chiudere la domanda. Mi sono allontanato da gsl e ora uso odeint quindi non l'ho provato. –

0

Perché sei preoccupato per la funzione statica in questo caso? Le variabili e/o oggetti dichiarati in una funzione statica non sono condivisi tra thread diversi a meno che non siano statici stessi (che nel tuo caso non lo sono).

Il tuo codice non riesce a fare qualcosa?

+0

non ora ma è una parte di un codice più grande che continuerò ad espandere. Sto usando statico per ora, ma preferirei avere una soluzione non statica. un altro vantaggio sarebbe capire 'bind' e' function' –

0

Mi dispiace, ma quello che stai cercando di fare non ha alcun senso. Qualunque problema di sicurezza dei thread ti preoccupi, non verranno risolti aggiungendo o rimuovendo la parola chiave static.

L'unico motivo per cui si dovrebbe rendere g non statico sarebbe se un'istanza di A fosse in qualche modo richiesta per l'operazione di g. E l'attuale implementazione di g non richiede tale istanza.

Nota è inoltre possibile rendere g una funzione globale, senza la parola chiave static. Non ci sarebbero differenze visibili nel tuo caso. Tuttavia è meglio che nel tuo caso lo stile abbia g nella classe che lo usa, come funzione statica.

Inoltre, Here è un materiale correlato sui puntatori alle funzioni membro (statiche/non statiche).

+0

nel mio codice completo, la funzione 'g' dipende dal membro' std :: function'. Ottengo un errore se faccio un uso statico 'g del membro ... nella funzione membro statico'. quindi devo rendere statico '' std :: function' ma poi ho un problema ad assegnargli una funzione da un'altra classe. –

Problemi correlati