简体   繁体   中英

Passing pointer to non-static member function

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.

The Problem

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.

The Solution

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM