【问题标题】:Pass C++ class object in lambda capture and convert it to void pointer to pass to a C API在 lambda 捕获中传递 C++ 类对象并将其转换为 void 指针以传递给 C API
【发布时间】:2020-04-08 18:32:56
【问题描述】:

我是函数库的新手。我想将 lambda 传递给最终将 std::function<void()> 转换为 void 指针的函数。我需要将此 void 函数传递给 C API。此 lambda 还将当前类对象作为捕获。这是代码sn-p。任何帮助表示赞赏:

class Animal{
    public:
        Animal(std::function<void()> func){}

        // call C API that takes in void(*)()
        call_c_api(func); // Somehow convert func to void *
};
class Cat{
    private:
        std::string m_name;
        Animal m_animal;
    public:
        static StaticCatFunc(Cat*instance){
               std::cout << "Name: " << instance->m_name <<"\n";
        }
        Cat(){
           m_animal = new Animal([this](){StaticCatFunc(this);})
        }
};

我需要实现上述功能。这不是继承相关的问题。我需要以某种方式将带有捕获的 lambda 转换为 void 指针。我读过带有捕获的 lambdas 不能转换为原始指针。有没有办法实现这个功能?任何帮助表示赞赏。

===========更新=========

c api 看起来像这样:

call_c_api(void (*handler)());

【问题讨论】:

  • 这是不可能的。您需要擦除捕获才能使其正常工作。 std::function&lt;void()&gt; 可能是也可能不是 void(*)(void)[]{} 是,[&amp;]{} 不是。
  • 没有显示“void 指针转换”的实际含义,没有太多可说的。在那之前,答案是:你不能。
  • 您需要擦除类型并传递上下文指针。例如:void c_api(void(*callback)(void*), void* context);。然后在c++中,创建上下文指针并将函数指针传递给c api。
  • @sturcotte06,你能解释一下吗?谢谢!
  • C API 将如何处理指针?它会作为函数调用它吗?还是只是将其存储并稍后传回给您?

标签: c++ c c++11 std-function stdbind


【解决方案1】:

您不能这样做,因为std::function 捕获是通过类型擦除实现的。它不能转换为 C 函数指针,除非它没有捕获的参数。为此,您需要使用 C 风格的回调调用。

// In a C header
void c_api(void(*callback)(void*), void* userdata);

// In a C++ header
struct MyStruct {
    MyStruct(std::function<void()> func) {
        _func = std::move(func);
        c_api(&MyStruct::CallbackFromC, this);
    }

    static void CallbackFromC(void* data) {
        MyStruct* self = reinterpret_cast<MyStruct*>(data);
        self->_func();
    }

    std::function<void()> _func;
};

请务必注意,调用回调时 MyStruct 必须仍然是有效指针,否则您将获得 SEGFAULT。

【讨论】:

  • 感谢您的帮助,但问题是我无法访问 C 源代码。我只有可以使用的API。
  • @sam91 如果 C API 没有为您提供将用户定义的值传递给回调的方法,那么您试图实现的目标无法直接完成。这需要将this 指针存储在全局(或线程局部)变量中,或者存储在特制的 thunk 中(这需要深入了解 CPU 的架构、指令集和汇编编程)。
  • @sam91 您实际使用的是哪个 C API?并非所有 C API 都使用回调参数来传递用户定义的数据,有时它们有一组单独的函数用于此目的,例如:void callback() { Animal *a = (Animal*) c_api_get_data(); ... }c_api_set_data(this); c_api(&amp;callback);
猜你喜欢
  • 1970-01-01
  • 2012-11-08
  • 2012-10-06
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多