将没有复制构造函数的类的指针传递给成员函数到Fortran

时间:2018-02-07 07:39:06

标签: c++ c++11 fortran function-pointers

我调用了一个Fortran函数,其第一个参数是一个函数,我想使用该函数的C ++成员函数,

void Obj::memberF(double* x,double* res)

Obj禁用了复制构造函数(这一点很重要,如下所示)。

Fortran子程序的格式为

subroutine solve(f,len,x)

f有两个参数xrhs,两者都是真正的数组。 len代表这些数组的长度。

(基本上,需要在非线性求解器库中调用残差函数)

为此目的,无论最终的C ++方法如何,我们都需要一个活页夹,如下所示

binder.f90

SUBROUTINE cpp_solve(cpp_f,len,x) BIND(C, NAME='cpp_solve')
  USE, INTRINSIC :: iso_c_binding, ONLY : c_int, c_float
  INTERFACE
    SUBROUTINE cpp_f(x,rhs) BIND(C)
      USE, INTRINSIC :: iso_c_binding, ONLY : c_float
      REAL(c_float) :: x(:)
      REAL(c_float) :: rhs(:)
    END SUBROUTINE cpp_f
  END INTERFACE
  INTEGER(c_int) :: len
  REAL(c_float) :: x(len)
  CALL solve(cpp_f,len,x)
END SUBROUTINE cpp_solve

对于C ++程序,首先,这些函数需要一个包装器

wrap.h

extern "C" {
  void cpp_f(double*,double*);
  void cpp_solve(void (Obj::*cpp_f)(double*,double*),int*,double*);
}

主程序如下

的main.cpp

#include "wrap.h"

int main {
  int len = 2;
  std::vector<double> x(len);
  // Multiple lines to initialize foo
  // Creating a global Obj is not feasible
  // ...
  Obj current_object(foo);

  // WHAT GOES HERE? 

  // cpp_solve(...,len,x);
}  

以下是我考虑过的一些方法,从最近的C ++功能开始,

1)请注意Obj的复制构造函数由于其他原因而被禁用,并且是约束。这使我无法使用std::bind附加当前实例并获取函数指针。

2)另外,定义另一个函数extra_function(Obj& obj, double*,...)然后使用lambda来返回obj.memberF也不是一个选项,因为这需要我指定一个捕获,给定自定义对象和我只需要一个函数指针。

3)更简单的选择是获取成员函数指针,然后按如下方式传递当前实例

typedef void (Obj::*fptr)(double*,double*);

fptr current_fPointer = &Obj::memberF;
cpp_solve(current_object.*current_fPointer,len,x);

这使我“无效使用非静态成员函数”错误。

我可以使用另一种方法来获取函数指针吗?

TBH,我实际上是尝试使用这些C ++ 11功能调用Fortran 77例程,因此这是一些改造。

1 个答案:

答案 0 :(得分:2)

如果这是一个单线程程序,一个实用的方法可以使用带有额外函数的全局指针变量

static Obj *g_obj;

static void extra_func(double *x1, double *x2)
{
    g_obj->memberF(x1, x2);
}

void call_f77(Obj *o1, int *len, double *x)
{
    g_obj = o1;
    cpp_solve(extra_func, len, x);
}

另一种方法,如果您可以修改Fortran代码(并且Fortran透明地可以以某种方式传递对象指针),您可以将相关对象通过Fortran隧道传送到extra_func,例如

static void extra_func(void *p, double *x1, double *x2)
{
    Obj *obj = static_cast<Obj*>(p);
    obj->memberF(x1, x2);
}

void call_f77(Obj *o1, int *len, double *x)
{
    cpp_solve(extra_func, o1, len, x);
}

在Fortran中(请原谅我,我从未见过任何Fortran代码):

SUBROUTINE solve(cpp_f, obj, len, x)
...
CALL cpp_f(obj, x, rhs)
...