C ++ 11 — как избежать статической функции-члена при использовании gsl с переполнением стека

Я хотел бы использовать GSL в классе C ++ без объявления функций-членов как 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;
};

Это сработало, но это грязное решение, потому что мне нужно было написать вспомогательную функцию. С лямбдами, функциями и связями должен быть способ, чтобы все было логично в классе.

8

Решение

Вы можете легко обернуть функции-члены, используя следующий код (который является хорошо известным решением)

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

Однако вы должны знать о снижении производительности std :: function перед тем, как помещать функции-члены в процедуру интеграции gsl. Увидеть шаблон против 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 (что критично для производительности, если ваш код выполняет тяжелые числовые вычисления). Так что даже несмотря на то, что обходной путь во втором примере кажется более громоздким, я бы предпочел шаблоны, а не std :: function.

8

Другие решения

GSL принимает функции C-типа “int (*)(char,float)” а не C ++ — тип “int (Fred::*)(char,float)”, Чтобы преобразовать функцию-член в функцию типа C, вам нужно добавить static,

увидеть Отличается ли тип «указатель на функцию-член» от «указатель на функцию»?

1

Почему вы беспокоитесь о статической функции в этом случае?
Переменные и / или объекты, объявленные в статической функции, не разделяются между различными потоками, если они сами не являются статическими (что в вашем случае не является).

Ваш код не может что-то сделать?

0

Извините, но то, что вы пытаетесь сделать, не имеет никакого смысла. Какие бы проблемы безопасности потоков вы ни беспокоили, они не будут решены путем добавления или удаления static ключевое слово.

Единственная причина, почему вы бы сделали g нестатичным будет, если экземпляр A было как-то требуется для gоперация. И текущая реализация g не требует такого экземпляра.

Обратите внимание, вы также можете сделать g глобальная функция, без static ключевое слово. Там не будет никакой видимой разницы в вашем случае. Однако лучше в вашем случае иметь g в классе, который использует его, как статическую функцию.

Также, Вот некоторый связанный материал об указателях на (статические / нестатические) функции-члены.

0
По вопросам рекламы [email protected]