簡體   English   中英

使用gsl和c ++時如何避免靜態成員函數

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

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

它工作但它是一個混亂的解決方案,因為我需要編寫輔助函數。 使用lambdas,function和bind,應該有一種方法可以讓類中的所有內容都符合邏輯。

您可以使用以下代碼輕松地包裝成員函數(這是一個眾所周知的解決方案)

 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 :: bind將成員函數包裝在std :: function中。 例:

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

但是,在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);
  }
};

在這種情況下,要調用成員函數,您需要以下內容

 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 :: function解釋了編譯器通常比std :: function更容易優化模板(如果你的代碼進行繁重的數值計算,這對性能至關重要)。 因此,即使第二個示例中的解決方法看起來更加繁瑣,我也更喜歡模板而不是std :: function。

GSL采用C類函數“int (*)(char,float)”而不是C ++ - 類型“int (Fred::*)(char,float)” 要將成員函數轉換為C類型函數,需要添加static

看到“指向成員函數的指針”的類型是否與“指向函數的指針”不同?

在這種情況下,為什么你擔心靜態功能? 靜態函數中聲明的變量和/或對象不會在不同的線程之間共享,除非它們本身是靜態的(在您的情況下它們不是靜態的)。

你的代碼沒有做某事嗎?

對不起,但是你要做的事沒有任何意義。 無論您擔心什么線程安全問題,都不會通過添加或刪除static關鍵字來解決這些問題。

唯一的原因,你為什么會做出g如果實例非靜態將是A在某種程度上需要g的操作。 並且g的當前實現不需要這樣的實例。

注意,您也可以使用g作為全局函數,而不使用static關鍵字。 在你的情況下沒有明顯的區別。 然而,在你的情況下,在使用它的類中使用g作為靜態函數是更好的風格。

另外, 這里有一些關於(靜態/非靜態)成員函數指針的相關資料。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM