如何将C ++函数指针(非静态成员函数)传递给预定义的C函数?

时间:2013-11-18 07:33:53

标签: c++ c templates function-pointers

我正在考虑使用http://users.ics.forth.gr/~lourakis/levmar/中的库,该库是用C语言编写的。

但是我将它包含在成员函数“dlevmar_der”中,它希望有两个函数指针作为其参数:

int dlevmar_der(
    void (*func)(double *p, double *hx, int m, int n, void *adata), 
    void (*jacf)(double *p, double *j, int m, int n, void *adata),  
    double *p,         /* I/O: initial parameter estimates. On output contains the estimated solution */
    double *x,         /* I: measurement vector. NULL implies a zero vector */
    int m,             /* I: parameter vector dimension (i.e. #unknowns) */
    int n,             /* I: measurement vector dimension */
    int itmax,         /* I: maximum number of iterations */
    double opts[4],
    double info[LM_INFO_SZ],
    double *work,
    double *covar,
    void *adata
)

我有以下简化模板类,其中包含两个非静态成员函数CallBack和MyJac。 (假设我在类中也有m_solution,m_info等所有其他属性):

Template<class F> 
class MyClass
{
    public: 
        typedef void (MyClass<F>::*FuncPtrType)(float*);

        void Start()
        {
            this->Run(&MyClass<F>::MyJac);
        }

    protected:
        void Callback(ValueType x[], ValueType result[], int m, int n, void* adata){ // some code }
        void MyJac(ValueType x[], ValueType result[], int m, int n, void* adata){ // some code }

        void Run(FuncPtrType func)
        {
             int iterCount = dlevmar_der(&MyClass<F>::Callback, func,
        (double*)&this->m_solution[0],
        (double*)&zero[0],
        this->m_function.NumberOfParameters,
        this->m_function.NumberOfFunctionValues,
        this->m_maxIterations,
        this->m_options,
        this->m_info,
        NULL,
        NULL,
        static_cast<void*>(this));
        }
}

但是,在调用Start()函数时,我在“运行”函数中收到错误,说:error C2664: 'slevmar_der' : cannot convert from 'void (__thiscall MyClass<F>::* )(float *,float *,int,int,void *)' to 'void (__cdecl *)(float *,float *,int,int,void *)

我的问题是dlevmar_der函数是否只能将函数指针指向静态成员函数?或者有什么方法可以使用dlevmar_der实现非静态成员函数吗?

3 个答案:

答案 0 :(得分:5)

你需要建立一个蹦床功能。

只需将this作为adata参数传递,然后编写一个回调函数,将adata强制转换为正确的类型指针并调用该方法。例如:

  void myFunc(double *p, double *hx, int m, int n, void *adata) {
      MyClass *self = static_cast<MyClass>(adata);
      self->funcMethod(p, hx, m, n, self->func_adata);
  }

答案 1 :(得分:1)

编写静态包装器

template<class F> 
class MyClass
{
    protected:
        void Callback(ValueType x[], ValueType result[], int m, int n) { 

        }

        static void CallbackWrapper(
              ValueType x[], ValueType result[], int m, int n, 
              void* adata) 
        { 
            static_cast<MyClass<T>*>(adata)->Callback(x, result, m, n);
        }

        void Run(FuncPtrType func)
        {
             int iterCount = dlevmar_der(
                 &MyClass<F>::CallbackWrapper, /*..*/ );
        }
};

答案 2 :(得分:0)

C ++成员函数指针不能与常规函数指针互换使用。

但是,您通常可以安全地使用静态成员函数指针,其中需要C函数指针。您的C API看起来允许您将自己的void*上下文参数传递给回调。您可以使用它将实例指针传递回静态方法,并使用它来调用您的isntance方法,如下所示:

static void StaticCallback(/* Args... */, void *user_data)
{
    MyClass *ptr = static_cast<MyClass*>(user_data);
    ptr->NonStaticCallback(/*args...*/);
}

(严格来说,你需要使用一个声明为extern "C"的免费(非成员)函数来进行转发,但静态方法通常很好。)