首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++ --如何将回调绑定到类方法而不需要静态?

C++ --如何将回调绑定到类方法而不需要静态?
EN

Stack Overflow用户
提问于 2020-05-31 11:11:42
回答 2查看 261关注 0票数 1

我有我的课:

代码语言:javascript
复制
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签名是:

代码语言:javascript
复制
esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);

其中wifi_promiscuous_cb_t的定义是:

代码语言:javascript
复制
typedef void (* wifi_promiscuous_cb_t)(void *buf, wifi_promiscuous_pkt_type_t type);

我想在类中使用mycallback方法,因此我不能这样使用:

代码语言:javascript
复制
  void Foo::registerMyCallback()
  {
    esp_wifi_set_promiscuous_rx_cb(&mycallback);
  }

我知道,如果我把我的方法变成静态的,我可能会用到类似的东西。是否存在将mycallback绑定到esp_wifi_set_promiscuous_rx_cb而不进行回调static的问题?

我尝试了以下几点:

代码语言:javascript
复制
esp_wifi_set_promiscuous_rx_cb(std::bind(&Foo::mycallback, this, std::placeholders::_1, std::placeholders::_2));

但我仍然有以下错误:

代码语言:javascript
复制
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'
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-31 17:25:39

您正在使用的是C包库。

因此,传递有效函数的唯一保证是传递C函数和C连接。然后,这个函数可以调用对象上的方法。

如果希望回调方法是非静态的,则需要存储一个指向回调对象的指针(或引用),以便回调函数能够找到它。(在大多数C回调函数中,您可以提供传递给回调的void*对象,但是这个接口似乎不允许这样做,因此您必须自己保存这个值)。

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2020-05-31 15:39:21

经过一些研究,我希望我找到了解决办法。诀窍是先绑定成员函数,然后从std::function获得函数指针。注意my_wifi_promiscuous_cb_tstd::function::target<>()的用法。

代码语言:javascript
复制
#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();
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62115330

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档