代码之家  ›  专栏  ›  技术社区  ›  Grzenio

C++中作为闭包工作的函数指针

  •  4
  • Grzenio  · 技术社区  · 14 年前

    C++中有没有方法有效地创建一个函数指针的闭包?我正在使用GNU科学图书馆,我必须创建一个 gsl_function . 这个函数需要在我创建它时有效地“关闭”几个可用的参数。是否有一个很好的技巧来创建一个闭包,这样我就不必在gsl_函数结构中将它们全部作为参数传递了?如果不是,我应该将指针传递给包含这些参数的数组吗?

    编辑 我尝试使用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 回复  |  直到 14 年前
        1
  •  2
  •   Ken Bloom    14 年前

    我在找到下面的代码。

    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
  •  2
  •   Viktor Sehr    14 年前

    看看这个 simple 组合boost::bind和boost::函数的示例。

        3
  •  2
  •   John    14 年前

    我猜从那些“GSLL”前缀中,库不是C++,而是普通C,这意味着它不拖动C++闭包(函子)。不能将C++函子传递给C函数。你必须传递空指针,交叉你的手指,重新解释,把它们丢进C遗忘。

        4
  •  1
  •   Ken Bloom    14 年前

    尽管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库都使用这种习惯用法,它们并不都为它使用一个结构(它们经常将它作为两个单独的参数传递给函数),因此自动转换并不总是可能的。