1

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.

6
  • If you want cpp_f to be C interoperable by the current Fortran standard, the dummy arguments cannot be assumed shape. Commented Feb 7, 2018 at 7:47
  • Yes, sorry about that. Commented Feb 7, 2018 at 7:56
  • Have you considered using std::function initialized by lambda e.g.: std::function<void(double* , double*)> foo = [&current_object](double* len, double* x) { current_object.memberF(len, x); }; ? Commented Feb 7, 2018 at 8:24
  • @francescalus do you have suggestions for how the length of arrays can be conveyed to the arguments in cpp_f? The prototype cannot be changed as it is part of the library. Commented Feb 7, 2018 at 9:04
  • 1
    If that's an accurate interface for cpp_f then you can find examples of how such a function can be interoperable in this question. Commented Feb 7, 2018 at 9:47

1 Answer 1

2

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)
...
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the approach and I had considered it actually. Unfortunately, I cannot create a global Obj as it will need foo, which involves multiple objects to be initialized, which make up the bulk of the program. I've edited my question to clarify this.
Not a global object, but a global pointer to the currently used/active object.
Worth a shot. I will wait for other answers though, given the presence of a global variable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.