[英]How to bind this pointer to static member function using thunk in 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.