2010-07-07 25 views
3

Est-il possible en C++ de créer efficacement une fermeture qui sera un pointeur de fonction? J'utilise la bibliothèque scientifique Gnu et je dois créer un gsl_function. Cette fonction doit effectivement "fermer" quelques paramètres disponibles lorsque je le crée. Existe-t-il une astuce pour créer une fermeture afin que je n'ai pas besoin de les passer tous en params dans la structure gsl_function? Si non, devrais-je juste passer un pointeur vers un tableau contenant ces paramètres?Pointeurs de fonction fonctionnant comme des fermetures en C++

EDIT J'ai essayé d'utiliser boost :: bind comme ceci:

#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; 
} 

mais je reçu le message d'erreur suivant:

/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 
+0

Pour que votre code fonctionne, la fonction F. doit avoir la signature double nomfonction (double, vide *). – Patrick

Répondre

2

Jetez un oeil à ce simple exemple de combinant boost :: bind et boost :: function.

+0

J'ai le code suivant: gsl_function F; F.fonction = & boost :: bind (intégrande, xi, t, _1, _2); et j'obtiens l'erreur de compilation suivante: /home/ga/svn/PhD/inflation/cpp/ioi/bondpricecalculator.cpp:20: erreur: impossible de convertir 'boost :: _ bi :: bind_t , boost :: _ bi :: valeur , boost :: arg <1>, boost :: arg <2>>> * 'à' double (*) (double, vide *) 'dans l'affectation. Qu'est-ce que j'oublie ici? – Grzenio

+0

Ce message d'erreur est difficile à lire et nous devons voir le code. Mettez à jour votre question ou en créer une nouvelle. –

+0

Cette réponse est totalement fausse, parce que le résultat n'est pas un pointeur de fonction - c'est un pointeur vers n'importe quel type d'objet boost :: function que vous avez créé avec boost :: bind –

2

Je devine que de tous ces préfixes "gsl_" que la bibliothèque est pas C++, mais simple C. Ce qui signifie qu'il n » t grok C++ fermures (foncteurs). Vous ne pouvez pas passer un foncteur C++ à une fonction C. Vous devrez passer des pointeurs de vide, croiser vos doigts et les réinterpréter dans l'oubli.

+0

C'est exact.C++ utilise des foncteurs plutôt que des fermetures, bien que les deux puissent être considérés comme effectivement équivalents dans de nombreuses circonstances. Une bibliothèque C ne peut pas être passée fermures/foncteurs. – Puppy

1

Bien que bradgonesurfing a donné une belle réponse qui fonctionnera sans aucune autre pensée pour convertir les fermetures en gsl_function s, je voudrais partager avec vous l'idiome pour faire une traduction directe de C++ en C.

vous Supposant ont la fermeture:

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

Vous convertir les traduire en un langage de pointeur de fonction équivalente comme suit:

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. 

De nombreuses bibliothèques C utilisent ce type d'idiome, et elles n'utilisent pas toutes une structure (elles le transmettent souvent comme deux paramètres distincts à la fonction), de sorte que la conversion automatique n'est pas toujours possible.

+0

ouais, c'est ce que j'ai fini par faire. – Grzenio