如何使用GSL用C时避免静态成员函数++(how to avoid static member fu

2019-06-18 15:39发布

我想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";
}

更新(1):

我试图改变gsl_monte_function G = { &g, 3, 0 };gsl_monte_function G = { bind(&A::g, this,_1,_2,_3), 3, 0 }; 但它没有工作

更新(2):我尝试使用指定的std ::函数成员函数 ,但它也不能工作。

更新(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;
};

它的工作,但它是一个混乱的解决方案,因为我需要写一个辅助功能。 随着lambda表达式,函数和约束,应该有办法让一切阶级内部的逻辑。

Answer 1:

可以使用下面的代码(这是一个公知的解决方案)容易包裹成员函数

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

然后你可以使用std ::绑定来包装成员函数在一个std ::功能。 例:

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

但是,你应该知道关于包装GSL积分程序内成员函数之前的std ::功能的性能损失。 见模板VS的std ::功能 。 为了避免这种性能损失(这可能会或可能不会对你至关重要的),你应该使用模板,如下图所示

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

在这种情况下,打电话给你需要一个成员函数以下

 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:链接模板VS的std ::函数解释说,编译器通常有一个更简单的时间比优化的std ::函数模板(如果你的代码是做重数值计算这对性能至关重要)。 因此,即使在艰难的第二个例子的解决办法似乎更麻烦,我宁愿比的std ::函数模板。



Answer 2:

GSL需要一个C型函数“int (*)(char,float)”而不是C ++ -型“int (Fred::*)(char,float)” 。 成员函数转换为C型功能,你需要添加static

见是“指针到成员函数”的类型从“指针到功能”有什么不同?



Answer 3:

为什么你担心在这种情况下,静态函数? 在一个静态函数声明的变量和/或对象,除非它们是静态的自己(在你的情况下,他们都没有)没有不同的线程之间共享。

是您的代码没有做什么?



Answer 4:

很抱歉,但你正在试图做的没有任何意义的。 无论线程安全问题,你很担心,他们将不会被添加或删除解决static关键字。

唯一的原因,你为什么会做出g如果实例非静态将是A在某种程度上需要g的操作。 和G目前的实现并不需要这样一个实例。

请注意,您还可以g一个全球性的功能,而static关键字。 会有你的情况没有明显的区别。 然而,最好的风格,你的情况有g ,其中利用它的类,静态函数。

另外, 这里是约指针(静态/非静止)成员函数一些相关的材料。



文章来源: how to avoid static member function when using gsl with c++