I have been trying to pass an interpolation function by reference as an argument to another function but I keep getting the following error:
error: could not convert '&AmrCoreAdv::interp_reta_from_R' from 'double (AmrCoreAdv::*)(double)' to 'std::function<double(double)'
There is a header file called AmrCoreAdv.H
where the interpolation function is declared as double interp_reta_from_R(double R)
and it is defined in another file. The interpolation function is passed as an argument to the state_rhs
function and is called as follows:
state_rhs(i, j, k, rhs_fab, state_fab, eta, dx[0], dx2, deta, eta2, two_over_eta, three_over_eta, e2_over_8pi2, &interp_reta_from_R);
The function state_rhs
takes in the following arguments:
state_rhs(int i, int j, int k,
amrex::Array4<amrex::Real> const& rhs_fab,
amrex::Array4<amrex::Real const> const& state_fab,
const amrex::Real eta,
const amrex::Real _dx,
const amrex::Real dx2,
const amrex::Real d_eta,
const amrex::Real eta2,
const amrex::Real two_over_eta,
const amrex::Real three_over_eta,
const amrex::Real e2_over_8pi2,
std::function<double (double)> interp_reta_from_R)
I am relatively new to C and am lost as to how to proceed. I have tried using typedef
and some other ways of defining the type of the interp_reta_from_R
function as an argument in the state_rhs
function but to no avail. I would really appreciate some guidance on this. Please let me know if you would require any additional information for debugging this issue. Thank you!
CodePudding user response:
A member function is not like a free function - it has a different type which includes the class, and it can't be called without an instance of the class.
The simplest thing is to pass a lambda function instead, capturing the object that should get its member called.
Assuming that the function is a member of *this
, replace the pointer-to-member with
[this](double d) { return interp_reta_from_R(d); }
CodePudding user response:
Pointer to member is not a regular pointer, it needs to come with its object.
Consider the following code:
struct S
{
double f(double);
};
//whatever
S s;
s.f(3.14);
The mental model for the call to f
can be sth like the following one (this is just a mental model, it has nothing to do with the standard, calling convention etc.):
f(&s, 3.14); //s address
For that reason, in order to transform a member function into a free function, it's object argument needs to be bound to it.
Modern C (C 11 onwards) has two means of doing this: std::bind
or lambda expressions. For pre-C 11 one can look-up boost::bind
which plays essentially the same role as its std
counterpart.
Note that lambdas (since C 11) are somewhat limited when it comes to move-only types, which means one might be stuck with bind
; should technical limitations not be the case use whatever suits your needs, taste and code conventions.
Also, note that object might be provided either by value (giving the created function object copy semantics) or reference/address. In the latter case, make sure the functor does not outlive the objects it is supposed to be referring to.
Example:
#include <functional>
struct S
{
double f(double) {return{};}
};
void ff(std::function<double(double)>){}
int main(int, char*[])
{
S s;
ff(std::bind(&S::f, s, std::placeholders::_1)); //bind by value
ff(std::bind(&S::f, &s, std::placeholders::_1)); //bind by address
ff([&s](double x){return s.f(x);}); //lambda with capture by reference
ff([s](double x)mutable{return s.f(x);}); //lambda capturing by value. Note mutable; lambdas by default capture by value as const objects!
}