Указатели на функции, работающие как замыкания в C ++ - PullRequest
4 голосов
/ 07 июля 2010

Есть ли способ в C ++ эффективно создать замыкание, которое будет указателем на функцию?Я использую Научную библиотеку Gnu, и мне нужно создать gsl_function .Эта функция должна эффективно «закрыть» пару параметров, доступных при ее создании.Есть ли хороший трюк для создания замыкания, чтобы мне не приходилось передавать их все как параметры в структуре gsl_function?Если нет, я должен просто передать указатель на массив, содержащий эти параметры?

EDIT Я пытался использовать boost :: bind так:

#include <gsl/gsl_integration.h>
#include <boost/bind.hpp>

#include "bondpricecalculator.h"
#include "functions.h"

double integrand (double xi, double t, double x, void * p) {
        Functions *functions = (Functions *) p;
        double vx = functions->v(x);
        return functions->rho0(x)*exp(vx * xi - 0.5 * vx * vx * t);
     }

double BondPriceCalculator::value(double t, double T, double xi)
{
    gsl_integration_workspace * w
         = gsl_integration_workspace_alloc (10000);

    gsl_function F;

    F.function = &boost::bind(integrand, xi, t, _1, _2);
    F.params = &functions;

    double integral_t;
    double integral_T;
    double error;

    int res = gsl_integration_qags(&F, T, 1e+14, 0, 1e-7, 10000, w, &integral_T, &error);
    if(res)
    {
        throw "Error intgrating";
    }

    int res = gsl_integration_qags(&F, T, 1e+14, 0, 1e-7, 10000, w, &integral_t, &error);
    if(res)
    {
        throw "Error intgrating";
    }

    return integral_T/integral_t;
}

но я получил следующее сообщение об ошибке:

/home/ga/svn/PhD/inflation/cpp/ioi/bondpricecalculator.cpp:20: error: cannot convert ‘boost::_bi::bind_t<double, double (*)(double, double, double, void*), boost::_bi::list4<boost::_bi::value<double>, boost::_bi::value<double>, boost::arg<1>, boost::arg<2> > >*’ to ‘double (*)(double, void*)’ in assignment

Ответы [ 4 ]

2 голосов
/ 07 июля 2010

Я нашел ниже код в.

http://bytes.com/topic/c/answers/657124-interface-problem

// Use in combination with boost::bind.
template<class F>
static double gslFunctionAdapter( double x, void* p)
{
    // Here I do recover the "right" pointer, safer to use static_cast
    // than reinterpret_cast.
        F* function = static_cast<F*>( p );
    return (*function)( x );
}

template<class F>
gsl_function convertToGslFunction( const F& f )
{
    gsl_function gslFunction;

    const void* p = &f;
    assert (p != 0);

    gslFunction.function = &gslFunctionAdapter<F>;
    // Just to eliminate the const.
    gslFunction.params = const_cast<void*>( p ); 

        return gslFunction;
}

и используйте это как

gslFunction gslF = convertToGslFunction( boost::bind( &Sde::drift, &sde, _1 ) );
2 голосов
/ 07 июля 2010

Я предполагаю из всех этих префиксов "gsl_", что библиотека не C ++, а простая C. Это означает, что она не вызывает замыкания C ++ (функторы).Вы не можете передать функтор C ++ функции C.Вам нужно будет обойти пустые указатели, скрестить пальцы и повторно интерпретировать их в C забвении.

2 голосов
/ 07 июля 2010

Взгляните на этот простой пример объединения boost :: bind и boost :: function.

1 голос
/ 08 июля 2010

Хотя bradgonesurfing дал хороший ответ, который будет работать для преобразования замыканий в gsl_function s без каких-либо дополнительных размышлений, я хотел бы поделиться с вами идиомой для прямого перевода с C ++ в C.

Предположим, у вас есть замыкание:

double a;
[&a](double x){return a+x;}

Вы должны преобразовать это в эквивалентную идиому указателя функции следующим образом:

struct paramsAPlusX{
    double* a;
    paramsAPlusX(double & a_):a(&a_){}
}
double funcAPlusX(double x, void* params){
   paramsAPlusX* p= (paramsAPlusX*)params;
   return *(p->a) + x;
}

//calling code:
double a;
paramsAPlusX params(a);
gsl_function f;
f.function=funcAPlusX;
f.params=&paramsAPlusX;
//use f here.

Многие библиотеки C используют этот тип идиом, и онине все используют для него структуру (они часто передают ее как два отдельных параметра функции), поэтому автоматическое преобразование не всегда возможно.

...