C++ - 如何将回调绑定到一个类的方法而不被静态化?

问题描述 投票:1回答:1

我有我的类。

class Foo
{
public:
  (...)    
private:        
    void mycallback(void* buff, wifi_promiscuous_pkt_type_t type);
    void registerMyCallback();
};

我有一个类: mycallback 是回调。

我想使用一个方法 esp_wifi_set_promiscuous_rx_cb 注册 mycallback 以便当检测到WiFi数据包时,这个回调方法将被执行。

这个 "回调 "方法的 esp_wifi_set_promiscuous_rx_cb 签名是。

esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);

凡是... wifi_promiscuous_cb_t 定义是。

typedef void (* wifi_promiscuous_cb_t)(void *buf, wifi_promiscuous_pkt_type_t type);

我想使用 mycallback 方法,因此我根本不能像这样使用。

  void Foo::registerMyCallback()
  {
    esp_wifi_set_promiscuous_rx_cb(&mycallback);
  }

我知道我可以使用类似的东西 如果我把我的方法变成静态的. 有什么办法可以让我绑定. mycallbackesp_wifi_set_promiscuous_rx_cb 而不进行回调 static?

我已经尝试了以下方法。

esp_wifi_set_promiscuous_rx_cb(std::bind(&Foo::mycallback, this, std::placeholders::_1, std::placeholders::_2));

但我还是出现了以下错误

cannot convert 'std::_Bind_helper<false, void (Foo::Foo::*)(void*, wifi_promiscuous_pkt_type_t), 
Foo::Foo*, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type 
to 
'wifi_promiscuous_cb_t {aka void (*)(void*, wifi_promiscuous_pkt_type_t)}' for argument '1'
c++ c++11 callback esp32
1个回答
1
投票

你使用的库是C包。因此,唯一能保证传递一个有效函数的方法是传递一个有C语言链接的C函数。这个函数就可以在你的对象上调用方法。

如果你想让回调方法是非静态的,你需要在某个地方存储一个指向回调对象的指针(或引用),让你的回调函数可以找到它。(在大多数C语言的回调函数中,你可以提供一个void*对象来传递给你的回调,但是这个接口似乎不允许这样做,所以你将不得不自己保存这个值)。

Foo*  myCBObject = nullptr;

extern "C" void myCB(void *buf, wifi_promiscuous_pkt_type_t type)
{
    try
    {
        myCBObject->mycallback(buff, type);
    }
    catch(...) {} // Don't allow exceptions to cross C linkage
}

...
// Your code.
void Foo::registerMyCallback()
{
    myCBObject = this;
    esp_wifi_set_promiscuous_rx_cb(myCB);
}

注意:你应该 在C库中注册静态成员函数。如果这样做能成功,那只是偶然的。不能保证一个静态函数有和C函数一样的调用约定(通常是这样,但不能保证)。


1
投票

经过一番研究,我希望我找到了解决方案。诀窍是先绑定成员函数,然后从std::function中获取函数指针。请注意以下用法 my_wifi_promiscuous_cb_tstd::function::target<>().

#include <iostream>
#include <functional>
using namespace std::placeholders;

// using fake definitions
extern "C"
{
  enum wifi_promiscuous_pkt_type_t {};
  typedef int32_t esp_err_t;
  typedef void (*wifi_promiscuous_cb_t)(void* buf, wifi_promiscuous_pkt_type_t type);
  typedef void my_wifi_promiscuous_cb_t(void* buf, wifi_promiscuous_pkt_type_t type);
  esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb)
  {
    return 0;
  }  
}

class Class
{
public:
  void mycallback(void* buff, wifi_promiscuous_pkt_type_t type) {}

  void registerMyCallback() {
    std::function<void(void*, wifi_promiscuous_pkt_type_t)> fun2 = std::bind(&Class::mycallback, this, _1, _2);
    esp_wifi_set_promiscuous_rx_cb(fun2.target<my_wifi_promiscuous_cb_t>());
  }
};

int main()
{
  Class c;
  c.registerMyCallback();
}
© www.soinside.com 2019 - 2024. All rights reserved.