使用gsl和c ++时如何避免静态成员函数

kir*_*gum 9 c++ callback gsl c++11 std-function

我想在c ++类中使用GSL而不将成员函数声明为static.原因是因为我不太了解它们,我不确定线程​​的安全性.从我读到的,std::function可能是一个解决方案,但我不知道如何使用它.

我的问题归结为如何static在声明中删除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";
}
Run Code Online (Sandbox Code Playgroud)

更新(1):

我试过换gsl_monte_function G = { &g, 3, 0 };gsl_monte_function G = { bind(&A::g, this,_1,_2,_3), 3, 0 };但是没用

更新(2):我尝试将std :: function赋值给成员函数,但它也不起作用.

更新(3) 最后我写了一个非成员函数:

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;
};
Run Code Online (Sandbox Code Playgroud)

它工作但它是一个混乱的解决方案,因为我需要编写辅助函数.使用lambdas,function和bind,应该有一种方法可以让类中的所有内容都符合逻辑.

Viv*_*nda 8

您可以使用以下代码轻松地包装成员函数(这是一个众所周知的解决方案)

 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);
   }
};
Run Code Online (Sandbox Code Playgroud)

然后你可以使用std :: bind将成员函数包装在std :: function中.例:

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

但是,在gsl集成例程中包含成员函数之前,您应该了解std :: function的性能损失.请参阅template vs std :: function.为了避免这种性能损失(可能对您而言可能不重要),您应该使用如下所示的模板

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);
  }
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,要调用成员函数,您需要以下内容

 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);   
Run Code Online (Sandbox Code Playgroud)

PS:链接模板vs std :: function解释了编译器通常比std :: function更容易优化模板(如果你的代码进行繁重的数值计算,这对性能至关重要).因此,即使第二个示例中的解决方法看起来更加繁琐,我也更喜欢模板而不是std :: function.