【发布时间】:2018-07-17 10:04:25
【问题描述】:
我有一个 Fortran 函数的调用,它的第一个参数是一个函数,我想为此使用 C++ 成员函数的形式,
void Obj::memberF(double* x,double* res)
Obj 禁用了复制构造函数(这变得很重要,如下所示)。
Fortran 子程序的格式为
subroutine solve(f,len,x)
f 有两个参数,x 和 rhs,它们都是实数数组。 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 例程,所以这是一些复古主义。
【问题讨论】:
-
如果您希望
cpp_f与当前的 Fortran 标准可互操作,则不能假定虚拟参数的形状。 -
是的,很抱歉。
-
您是否考虑过使用由 lambda 初始化的
std::function,例如:std::function<void(double* , double*)> foo = [&current_object](double* len, double* x) { current_object.memberF(len, x); };? -
@francescalus 你对如何将数组长度传递给 cpp_f 中的参数有什么建议吗?原型无法更改,因为它是库的一部分。
-
如果这是
cpp_f的准确接口,那么您可以在 this question 中找到此类函数如何可互操作的示例。
标签: c++ c++11 fortran function-pointers