【问题标题】:Passing pointer to non-static member function将指针传递给非静态成员函数
【发布时间】:2017-01-22 21:25:56
【问题描述】:

我有一个类的非静态成员函数:

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;
}

我想将它传递给cubature,这要求它采用以下形式:

int f(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval)

我考虑过使用std::mem_fn,但如果我使用:

auto bla = std::mem_fn(&Band::overlap);

我的电话是:

bla(band_obj, ....)

哪个容积不接受。然后我考虑使用 lambdas,但我读到我只能转换非捕获 lambdas,因此我无法捕获 band_obj。

我意识到,有人问过这个问题的变体,我试过了,但似乎没有一个有效。

【问题讨论】:

  • 寻找std::bind...
  • @barakmanos 绑定不起作用。 f 是指向 C 函数的指针,例如:没有 this 参数。

标签: c++ function-pointers member-function-pointers


【解决方案1】:

问题

我们希望f 成为指向非静态成员函数的指针并且 作为常规函数调用——没有this 指针。 std::functionlambda 和所有这些解决方案都不起作用 - 我们仍然需要以某种方式传递他们的 this

解决方案

Cubature 提供了fdata 参数来传递给你的函数,我们可以用它来传递this 指针:

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);
}

然后用this参数作为fdata调用hcubature

hcubature(1, f, static_cast<void*>(band), 
          3, xmin, xmax, 0, 0, 1e-4, ERROR_INDIVIDUAL, &val, &err);

【讨论】:

  • 这种方法的变体有效。我的 *fdata 现在是一个包含 的元组的 static_cast,这似乎有效。谢谢!
【解决方案2】:

你不能。

Cubature 是一个 C 函数,它需要一个 C 函数指针作为参数。

在 C++ 中,绝对没有任何东西可以从成员函数、std::mem_fnstd::function、lambda 或除了普通的非成员 extern "C" 函数之外的任何其他东西生成 C 兼容函数指针指针。

您可以编写一个普通的非成员 extern "C" 函数,并使其使用作为 `void* 传递给它的 Band* 值。

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(...) ...
}

当然,首先要做的是围绕hcubature_v 编写一个接受任何C++ 可调用对象的C++ 包装模板。

【讨论】:

  • " 在 C++ 中绝对没有任何东西可以生成与 C 兼容的函数指针" -> 如果 lambda 没有捕获,则可以将其隐式转换为与 c 兼容的函数指针。以signal(SIGTERM, [](void*){...}); 为例。
  • @dascandy non-capturing-lambda 就是一个普通的普通函数。
  • @dascandy 我刚刚意识到正式情况并非如此。这样的函数指针将没有 C 链接,因此不会与 C 兼容,尽管大多数实现会让你侥幸逃脱。
  • 它将转换为适当调用约定的函数指针类型。链接仅在您需要链接到它时才相关 - 但由于它是传入的参数,因此不是这种情况。
  • @dascandy 我的标准副本说“有一个公共的非虚拟非显式 const 转换函数指向具有 C++ 语言链接的函数的指针”。非规范性注释说“特定语言链接可能与表示具有外部链接或特定调用约定的对象和函数名称的特定形式相关联”,并且它是标准讨论调用约定的唯一地方。
【解决方案3】:

在 Cubat 中它说:

F 的 FDATA 参数等于传递给的 FDATA 参数 hcubature——调用者可以使用它来传递任何额外的 根据需要将信息传递给 F

所以你可以创建一个静态代理函数:

static int Band::overlap_static(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval) 
{
  ((Band *)fdata)->overlap(ndim, x, fdim, fval);
}

然后您可以调用hcubature,将当前的Band 指针作为第三个参数,将Band::operlap_static 作为函数指针。当然,然后你给管理*data 不同。

【讨论】:

  • 您可以在调用中的 lambda 就地执行此操作。由于您从 fdata 转换并且没有捕获其他任何内容,因此它将转换为与 C 兼容的函数指针。
【解决方案4】:

好吧,那是行不通的。

void *data_p 是传递状态的参数的一部分,但 Band::overlap 使用 void *data_p Band* this 来达到此目的。

解决方案:

/*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);
}

【讨论】:

    【解决方案5】:

    你可以使用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.
    

    我选择使用一些using 语句来清理代码。

    【讨论】:

    • 这不起作用:注意:候选函数不可行:没有来自 'std::function' 的已知转换(又名 'function, void *, unsigned int, double *)>') 到 'integrand' (aka 'int ()(unsigned int, const double *, void *, unsigned int, double *)') 用于第二个参数 int hcubature (无符号 fdim, 被积函数 f, void *fdata,
    猜你喜欢
    • 2014-03-06
    • 1970-01-01
    • 2012-08-01
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多