cómo evitar la función de miembro estático cuando se usa gsl con c ++

Me gustaría usar GSL dentro de una clase de C ++ sin declarar funciones de miembros como static . La razón de esto es porque no los conozco demasiado bien y no estoy seguro sobre la seguridad de los hilos. Según lo que leí, std::function podría ser una solución, pero no estoy seguro de cómo usarlo.

Mi pregunta se reduce a cómo puedo eliminar la static en la statement de 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"; } 

Actualización (1) :

Intenté cambiar gsl_monte_function G = { &g, 3, 0 }; a gsl_monte_function G = { bind(&A::g, this,_1,_2,_3), 3, 0 }; pero no funcionó

Actualización (2) : traté de usar la asignación de la función std :: a una función miembro, pero tampoco funcionó.

Actualización (3) al final escribí una función no miembro:

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

Funcionó, pero es una solución desordenada porque necesitaba escribir una función de ayuda. Con lambdas, función y enlace, debería haber una manera de tener todo lo lógico dentro de la clase.

Puede envolver fácilmente las funciones miembro usando el siguiente código (que es una solución bien conocida)

  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); } }; 

Luego puede usar std :: bind para envolver la función miembro en una función std ::. Ejemplo:

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

Sin embargo, debe conocer las penalizaciones de rendimiento de la función std :: antes de ajustar las funciones de los miembros dentro de la rutina de integración de gsl. Ver plantilla vs std :: función . Para evitar este golpe de rendimiento (que puede o no ser crítico para usted), debe usar plantillas como se muestra a continuación

 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); } }; 

En este caso, para llamar a una función miembro necesita la siguiente

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

PD: la plantilla de enlace vs std :: function explica que el comstackdor generalmente tiene un tiempo más fácil para optimizar las plantillas que std :: function (que es crítico para el rendimiento si su código realiza cálculos numéricos pesados). Así que incluso la solución del segundo ejemplo parece más engorrosa, preferiría plantillas que std :: function.

GSL toma las funciones tipo C “int (*)(char,float)” lugar de C ++ – tipo “int (Fred::*)(char,float)” . Para convertir una función de miembro a la función de tipo C, necesita agregar static .

ver ¿Es diferente el tipo de “función de puntero a miembro” de “puntero-a-función”?

¿Por qué estás preocupado por la función estática en este caso? Las variables y / o objetos declarados en una función estática no se comparten entre diferentes subprocesos a menos que sean estáticos ellos mismos (que en su caso no son).

¿Tu código no puede hacer algo?

Lo siento, pero lo que estás tratando de hacer no tiene ningún sentido. Independientemente de los problemas de seguridad de los hilos que le preocupen, no se resolverán añadiendo o eliminando la palabra clave static .

La única razón por la que harías g no estático sería si se requiriera de algún modo una instancia de A para la operación de g . Y la implementación actual de g no requiere dicha instancia.

Tenga en cuenta que también puede hacer que g una función global, sin la palabra clave static . No habría diferencia visible en su caso. Sin embargo, es mejor estilo en su caso tener g en la clase que hace uso de él, como una función estática.

Además, este es un material relacionado acerca de las funciones de los miembros (estáticos / no estáticos).