I've got a non-static member function of a class:
int Band::overlap(unsigned dim, const double *x, void *data_p, unsigned fdim,
double *retval){
int *data = (int*) data_p;
// data[0] = m; data[1] = n; data[2] = k_ind; data[3] = b
cmplx result = (this->U(x[0], x[1], x[2], data[2], data[0])).adjoint()
* this->U(x[0], x[1], x[2], data[2] + data[3], data[1]);
retval[0] = result.real();
retval[1] = result.imag();
return 0;
}
and I would like to pass it to cubature , which requires it to be of the following form:
int f(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval)
I considered using std::mem_fn , but if I use:
auto bla = std::mem_fn(&Band::overlap);
my call would be:
bla(band_obj, ....)
which cubature doesn't accept. I then considered using lambdas, but I read that I can only convert non-capture lambdas, therefore I can't capture band_obj.
I realize, that variations of this question have been asked, I tried them und non of them seem to work.
In Cubator it says:
The FDATA argument of F is equal to the FDATA argument passed to hcubature—this can be used by the caller to pass any additional information through to F as needed
So you can create a static proxy function:
static int Band::overlap_static(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval)
{
((Band *)fdata)->overlap(ndim, x, fdim, fval);
}
You then can call hcubature
with the current Band
pointer as third argument and Band::operlap_static
as the function pointer. Of course then you gave to manage *data
differently.
You can't.
Cubature is a C function that expects a C function pointer as a parameter.
There is absolutely nothing whatsoever in C++ that can make a C-compatible function pointer from a member function, an std::mem_fn
, an std::function
, a lambda, or anything else except a plain non-member extern "C"
function pointer.
You can write a plain non-member extern "C"
function and make it use a Band*
value passed to it as a `void*.
Band* band;
hcubature_v(fdim, overlap_adapter, static_cast<void*>(band), ...);
extern "C" int overlap_adapter(unsigned ndim, unsigned npts,
const double *x, void *fdata,
unsigned fdim, double *fval)
{
Band* band = static_cast<Band*>(fdata);
... band->overlap(...) ...
}
Of course the first thing to do is to write a C++ wrapper template around hcubature_v
that accepts any C++ callable object.
We want f
to be a pointer to non-static member function and to be called as a regular function - without the this
pointer. std::function
, lambda
and all of these solutions would not work - we still need to pass their this
somehow.
Cubature
provides the fdata
argument to pass it to your function, we could use it to pass the this
pointer:
int f(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval) {
Band *band = static_cast<Band*>(fdata);
return band->overlap(ndim, x, fdim, fval);
}
And then call hcubature
with the this
parameter as fdata
:
hcubature(1, f, static_cast<void*>(band),
3, xmin, xmax, 0, 0, 1e-4, ERROR_INDIVIDUAL, &val, &err);
Well, that's not going to work.
void *data_p
is part of the argument to pass state, but Band::overlap
uses both void *data_p
and Band* this
for that purpose.
Solution:
/*static*/ int Band::overlap(
unsigned dim, const double *x, void *data_p, unsigned fdim, double *retval)
{
return static_cast<Band*>(data_p)->overlap(dim,x,fdim, retval);
}
You could use std::function
:
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
using std::placeholders::_4;
using std::placeholders::_5;
using fn_signiture = int(unsigned, const double*, void*, unsigned, double*)
std::function<fn_signiture> pointer = std::bind(&Band::overlap,this,_1, _2, _3, _4, _5);
//"this" can be replaced with a pointer to a specific instance of a Band.
I chose to use a few using
statements in order to clean up the code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.