将GSL与C 一起使用时,如何避免静态成员函数

how to avoid static member function when using gsl with c++

本文关键字:何避免 静态成员 函数 GSL 一起      更新时间:2023-10-16

我想在C 类中使用GSL,而不声明成员函数为static。原因是因为我不太了解它们,我不确定线程安全。从我阅读的内容来看,std::function可能是一个解决方案,但我不确定如何使用。

我的问题归结为如何在g声明中删除static

#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 };,但它不起作用

update(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;
};

它起作用,但这是一个凌乱的解决方案,因为我需要编写一个辅助功能。使用lambdas,功能和绑定,应该有一种方法可以使所有逻辑中的所有内容都在类中。

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

 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 ::功能的性能惩罚。请参阅模板与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 :: function。

gsl采用C型功能“int (*)(char,float)”而不是C - 类型“int (Fred::*)(char,float)”。要将成员函数转换为C型函数,您需要添加static

请参阅"指针到会员功能"的类型与"指针到功能"不同?

为什么在这种情况下您担心静态功能?除非存在静态函数,否则在静态函数中声明的变量和/或对象,除非它们本身是静态的(在您的情况下它们不是静态)。

您的代码无法做某事?

对不起,但是您要做的事情没有任何意义。无论您担心什么线程安全问题,都不会通过添加或删除static关键字来解决它们。

如果g的操作需要以某种方式进行A实例,则您将进行g非静态的唯一原因。G当前的实现不需要这样的实例。

注意,您还可以使g成为全局函数,而无需static关键字。您的情况没有明显的区别。但是,在您的情况下,将使用g作为静态功能是更好的样式。

另外,这里是有关指针(静态/非静态)成员功能的一些相关材料。