Reputation: 262
I have a call to a Fortran function, the first argument of which is a function, for which I would like to use a C++ member-function of the form,
void Obj::memberF(double* x,double* res)
with Obj
having the copy-constructor disabled (and this becomes important as shown below).
The Fortran subroutine is of the form
subroutine solve(f,len,x)
with f
taking two arguments, x
and rhs
, both of which are real arrays. len
stands for the length of these arrays.
(Essentially, need to call the residue function in a non-linear solver library)
For this purpose, irrespective of the eventual C++ approach, we will need a binder and is as follows
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
For the C++ program, first, a wrapper is needed for these functions
wrap.h
extern "C" {
void cpp_f(double*,double*);
void cpp_solve(void (Obj::*cpp_f)(double*,double*),int*,double*);
}
The main program is as follows
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);
}
Below are a few approaches I've considered, starting with recent C++ features,
1) Note that the copy-constructor of Obj
has been disabled for other reasons and is the constraint. This prevents me from using std::bind
to attach the current instance and obtain a function pointer.
2) Also, defining another function extra_function(Obj& obj, double*,...)
and then using a lambda to just return obj.memberF
is not an option either, as that would require me to specify a capture, given the custom object and I need a function pointer only.
3) A simpler option would be to just obtain the member function pointer and then, pass the current instance as follows
typedef void (Obj::*fptr)(double*,double*);
fptr current_fPointer = &Obj::memberF;
cpp_solve(current_object.*current_fPointer,len,x);
This gives me the 'invalid use of non-static member function' error.
Is there an alternative approach I could use to obtain the function pointer?
TBH, I'm actually trying to call a Fortran 77 routine using these C++11 features, so that's some retrofuturism.
Upvotes: 1
Views: 301
Reputation: 74088
If this is a single threaded program, a pragmatic approach could use a global pointer variable with an extra function
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);
}
Another approach, if you can modify the Fortran code (and Fortran transparently can pass object pointers somehow), you may tunnel the relevant object through Fortran to the extra_func
, e.g.
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);
}
and in Fortran (please forgive me, I've never seen any Fortran code):
SUBROUTINE solve(cpp_f, obj, len, x)
...
CALL cpp_f(obj, x, rhs)
...
Upvotes: 2