come evitare la funzione di membro statico quando si usa gsl con c ++

Vorrei usare GSL all’interno di una class c ++ senza dichiarare le funzioni membro come static . Il motivo è perché non li conosco troppo bene e non sono sicuro della sicurezza dei thread. Da quanto ho letto, std::function potrebbe essere una soluzione, ma non sono sicuro di come usarlo.

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

 #include #include  #include  #include  #include  #include  #include  #include  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 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"; } 

Aggiornamento (1) :

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

Aggiornamento (2) : ho provato ad utilizzare l’ assegnazione di std :: function a una funzione membro, ma non ha funzionato neanche.

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

     double gmf (double *k, size_t dim, void *params) { auto *mf = static_cast(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 class.

    Puoi facilmente racchiudere le funzioni membro usando il seguente codice (che è una soluzione ben nota)

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

    Quindi puoi usare std :: bind per avvolgere la funzione membro in una funzione std ::. Esempio:

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

    Tuttavia, dovresti essere a conoscenza delle penalizzazioni prestazionali di std :: function prima di avvolgere le funzioni membro all’interno della routine di integrazione di gsl. Vedi template vs std :: function . Per evitare questo impatto sulle prestazioni (che potrebbe essere o non essere fondamentale per te), devi utilizzare i modelli come mostrato 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(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 Fp(ptr); gsl_function *F = static_cast(&Fp); 

    PS: la maschera di collegamento 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 tuo codice sta eseguendo pesanti calcoli numerici). Quindi anche la soluzione alternativa nel secondo esempio sembra più complessa, preferirei i template rispetto a std :: function.

    GSL utilizza le funzioni di tipo C “int (*)(char,float)” piuttosto che C ++ – tipo “int (Fred::*)(char,float)” . Per convertire una funzione membro nella funzione di tipo C, è necessario aggiungere static .

    vedi Il tipo di “funzione puntatore-membro” è diverso da “puntatore-a-funzione”?

    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 sta facendo qualcosa?

    Scusa, 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 dovresti rendere g non-statico sarebbe se un’istanza di A fosse in qualche modo richiesta per il funzionamento di g . E l’attuale implementazione di g non richiede tale istanza.

    Nota puoi anche rendere g una funzione globale, senza la parola chiave static . Non ci sarebbero differenze visibili nel tuo caso. Comunque è meglio che nel tuo caso sia meglio avere g nella class che ne fa uso, come funzione statica.

    Inoltre, ecco alcuni materiali correlati sui puntatori alle funzioni membro (statiche / non statiche).