【问题标题】:Converting a lambda to function pointer typedef将 lambda 转换为函数指针 typedef
【发布时间】:2018-06-15 18:04:03
【问题描述】:

我有一个第 3 方 API,它有一个函数,该函数将函数指针作为参数(示例类型):

// defined in "Api.h"
typedef int (*Callback) (int x); 

unsigned char ApiCall(int p, Callback cb);


int ApiCall(int p, Callback cb) {
   return cb(p);
}

我正在尝试使用类实例方法与此 API 进行交互;这是一个示例类:

class ApiWrapper {
    public:
        int ApiCallback(int x) { return this->factor_ * x; }

        static int WorkingApiCallback(int x) { return 3 * x; }

        ApiWrapper(int f) { this->factor_ = f; }

    private:
        int factor_;
} 

还有一个要测试的主要功能:

#include <iostream>
#include <functional>

int main() {
    ApiWrapper a(2);

    using std::placeholders::_1;
    std::function<int(int)> lambda = std::bind( &ApiWrapper::ApiCallback, a, _1 );

    std::cout << "Class: "  << a.ApiCallback(21) << std::endl;
    std::cout << "Lambda: " << lambda(21) << std::endl;
    std::cout << "Static ApiCall:" << ApiCall(21, ApiWrapper::WorkingApiCallback) << std::endl;

    // NOT WORKING 
    std::cout << "Static ApiCall:" << ApiCall(21, lambda) << std::endl;
    std::cout << "Static ApiCall:" << ApiCall(21, this.ApiCallback) << std::endl;    

    return 0;
}

有没有办法在不使用static 成员的情况下实现这一点;因为每次第 3 方库调用回调时,我都需要关联/使用状态。

谢谢!

【问题讨论】:

  • 指向非static 类方法的指针与类C 函数指针不兼容,因为它们将this 指针作为第一个参数传递。 IE。 class ApiWrapper { int ApiCallback(int x); }; 中的方法ApiCallback 在内部表示为int ApiCallback (ApiWrapper* this, int x);。现在很明显为什么它与typedef int (*Callback) (int x);不兼容
  • 嗯,谢谢你的评论,是的,我想,希望有一个解决方法或者我可能会丢失一些东西,这将迫使我跟踪静态成员内部的状态:(
  • 嗯.. 状态需要存储在某个地方,它可以传递给函数(需要一个额外的参数,使签名不同,因此不兼容),或者全局(不需要将其传递给函数 - 不需要更改函数签名)。
  • 最后一个你可以像这样调用std::cout &lt;&lt; "Static ApiCall:" &lt;&lt; ApiCall(21, ApiWrapper{2}.ApiCallback) &lt;&lt; std::endl;
  • 你确定api回调的x参数是int,而不是void*?

标签: c++ c++11 lambda callback


【解决方案1】:

您将不得不以某种方式将非成员与函数指针相关联,因为它不接受任何类型的上下文参数。您将在某个时候拥有一个非成员函数,这是无法解决的。而且该函数不能是捕获 lambda。

一种选择是拥有一个(可能是线程本地的)全局指针来保存实例。

即你这样做:

myType * glbInst;
..void someFunc()
{
 myType myInst;
  glbInst = &myInst;
  apiCall([] (int)  glbInst->member(x); });
}

另一个选择是使用 libffi 的闭包系统在运行时创建一个函数,并让实例成为保存数据的一部分。我经常使用这种模式,但在这里粘贴有点复杂。

【讨论】:

  • 感谢您的回复!,> 我经常使用这种模式,但在这里粘贴有点复杂。也许是粘贴箱的链接?
【解决方案2】:

有没有办法在不使用静态成员的情况下实现这一点;

有一个骇人听闻的解决方案。

  1. 定义一个非成员函数。
  2. 存储指向非成员函数可以访问的对象的指针。
  3. 从非成员函数调用对象的成员函数。

ApiWrapper* objectForCallback = NULL; 

int  NonMemberFunction(int x)
{
   assert(objectForCallback != NULL);
   return objectForCallback->ApiCallback(x);
}

以及上述工作的设置:

ApiWrapper a(2);
objectForCallback = &a;

现在你可以使用了:

std::cout << "Static ApiCall:" << ApiCall(21, NonMemberFunction) << std::endl;    

【讨论】:

    猜你喜欢
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    • 2013-03-17
    • 1970-01-01
    • 2015-03-31
    • 2022-01-16
    • 2012-11-21
    • 2011-05-16
    相关资源
    最近更新 更多