4


0

C ++でクロージャとして機能する関数ポインタ

関数ポインタとなるクロージャを効果的に作成する方法はC ++にありますか? Gnu Scientific Libraryを使用していますが、http://www.network-theory.co.uk/docs/gslref/Providingthefunctiontosolve.html [gsl_function]を作成する必要があります。 この関数は、作成時に使用可能ないくつかのパラメーターを効果的に「閉じる」必要があります。 gsl_function構造体のすべてのパラメーターとしてクロージャーを渡す必要がないように、クロージャーを作成する素晴らしいトリックはありますか? そうでない場合、これらのパラメータを含む配列へのポインタを渡すだけですか?

*編集*私はこのようにboost

bindを使用しようとしました:

#include
#include

#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, boost::_bi::value, boost::arg<1>, boost::arg<2> > >*’ to ‘double (*)(double, void*)’ in assignment

4 Answer


2


boost

bindとboost :: functionを組み合わせたこのhttp://www.boost.org/doc/libs/1_43_0/libs/bind/bind.html#with_boost_function[simple]の例をご覧ください。


2


以下のコードを見つけました。

// Use in combination with boost::bind.
template
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( p );
    return (*function)( x );
}

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

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

    gslFunction.function = &gslFunctionAdapter;
    // Just to eliminate the const.
    gslFunction.params = const_cast( p );

        return gslFunction;
}

そしてこれを

gslFunction gslF = convertToGslFunction( boost::bind( &Sde::drift, &sde, _1 ) );


2


これらすべての「gsl_」プレフィックスから、ライブラリはC ではなく、プレーンCであると推測しています。 つまり、C のクロージャー(ファンクター)を理解できません。 C ++ファンクタをC関数に渡すことはできません。 無効なポインターを渡し、指を交差させて、それらをC oblivionに再解釈する必要があります。


1


bradgonesurfingはクロージャを `gsl_function`に変換するのに有効な素晴らしい答えを与えましたが、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ライブラリはこの種のイディオムを使用しますが、すべてが構造体を使用しているわけではないため(関数に2つの別個のパラメーターとして渡すことが多いため)、自動変換が常に可能とは限りません。