11

メンバー関数を として宣言せずに 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::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;
};

うまくいきましたが、ヘルパー関数を書く必要があったため、面倒な解決策です。ラムダ、関数、およびバインドを使用すると、クラス内ですべてを論理的にする方法が必要です。

4

4 に答える 4

9

次のコードを使用してメンバー関数を簡単にラップできます (これはよく知られているソリューションです)。

 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 のパフォーマンス ペナルティについて注意する必要があります。テンプレートと 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: リンクテンプレートと std::functionは、通常、コンパイラは std::function よりもテンプレートを最適化する方が簡単であることを説明しています (コードが大量の数値計算を行っている場合、これはパフォーマンスにとって重要です)。したがって、2 番目の例の回避策はより面倒に思えますが、std::function よりもテンプレートを使用したいと思います。

于 2013-08-12T07:21:47.030 に答える
1
于 2014-06-18T21:14:04.077 に答える
0

申し訳ありませんが、あなたがやろうとしていることは意味がありません。心配しているスレッドセーフの問題が何であれ、staticキーワードを追加または削除しても解決されません。

g非静的にする唯一の理由は、のインスタンスAが何らかの形でgの操作に必要な場合です。そして、gの現在の実装はそのようなインスタンスを必要としません。

キーワードgなしでグローバル関数を作成することもできることに注意してください。staticあなたの場合、目に見える違いはありません。gただし、静的関数として、それを使用するクラスに含める方が、あなたの場合のスタイルの方が優れています。

また、(静的/非静的)メンバー関数へのポインターに関するいくつかの関連資料があります

于 2012-10-29T17:30:45.413 に答える
0

この場合、なぜ static 関数が心配なのですか? 静的関数で宣言された変数および/またはオブジェクトは、それら自体が静的でない限り、異なるスレッド間で共有されません(あなたの場合はそうではありません)。

あなたのコードは何かをするのに失敗していますか?

于 2012-10-29T04:40:34.380 に答える