0

I want to use an slatec subroutine (fortran) in C++. Usually these subroutines take subroutines/functions as arguments.

I have a class that performs some calculations and I would like to call a subroutine with a functor as an argument. Why? because the functor could access information from the main class.

These slatec subroutines do not allow to take an state or void* parameter.

A minimal example would be:

// compile with 
// g++ dgaus.cpp -lstdc++ -lgfortran -lslatec -Wall -g

#include <iostream>

extern "C"
{
// a not complicated subroutine in slatec
void dgaus8_(void(f)(double* x), double* a, double* b, double* err, double* ans,
            int* ierr);
};

// example function
inline void f(double* x) {
  *x = 3.0*(*x)*(*x);
}

// what i want/need is to use the following instead of the simple function above,
// I will have states and internals that change.
struct functor{
  functor() { }

  functor(double c_): c(c_) { }

  void operator()(double* x){
    *x = c*(*x)*(*x);
  }

  double c;//<! this will be a complicated object that changes
};

int main(int argc, char **argv) {

  {
    double ans=0.0;
    double a=1.0;
    double b=3.0;
    double err=0.0001;
    int ierr=0;

    // works
    dgaus8_(f, &a, &b, &err, &ans, &ierr);

    std::cout << "\n@> Answer : " << ans;
    std::cout << "\n@> Error : " << err;
    std::cout << "\n@> Flag : " << ierr;
    std::cout << "\n";

  }

  {    
    double ans=0.0;
    double a=1.0;
    double b=3.0;
    double err=0.0001;
    int ierr=0;

    double c = 3.0;

    // in the full code c is an object that calls 
    // dgaus8_, and functor is a member of it.
    // f = new functor(this);
    functor *f2 = new functor(c);

    // doesn't work
    dgaus8_(*f2, &a, &b, &err, &ans, &ierr);

    std::cout << "\n@> Answer : " << ans;
    std::cout << "\n@> Error : " << err;
    std::cout << "\n@> Flag : " << ierr;
    std::cout << "\n";

    delete(f2);  
  }
  return 0;
}

I got the error:

gaus.cpp: In function ‘int main(int, char**)’:
dgaus.cpp:64:43: error: cannot convert ‘functor’ to ‘void (*)(double*)’ for argument ‘1’ to ‘void dgaus8_(void (*)(double*), double*, double*, double*, double*, int*)’
     dgaus8_(*f2, &a, &b, &err, &ans, &ierr);

Is it possible to use a functor instead of a regular function when calling extern fortran functions?

My actual "design", solver calls slatec subroutine functor as parameter,

class sys

 void solver(...)
 func functor(..)

functor
 functor(s)
 sys s
 operator()
   functor access and call methods from s

or solver calls slatec subroutine function as parameter,

class

 void solver
 void function

what should be a correct design if you want to pass a function to fortran suboroutine, but this function is a result of a construction with many parameters an undetermined states within the calling class?

Caos21
  • 168
  • 1
  • 12

0 Answers0