C++ 成员函数作为回调

C++ Member function as a callback

我正在使用名为 websocket 的静态 class,它侦听 websocket(因此得名)并在收到数据后调用回调函数。我创建了以下声明

typedef int (*cb)(Json::Value &json);

static void websocket::init();
static void websocket::listen(cb callback, const char* address);

我还有一个名为 app 的 class,它应该包含作为成员函数的回调,因为它正在使用成员 属性 连接到数据库:

int app::callback(Json::Value& json)
{
    this->db->insert(json);
};

我在 app 中调用 websocket::listen() 函数,如下所示:

void app::start()
{
    websocket::listen(std::mem_fn(&app::callback), this->path);
}

我收到一条错误消息 error: cannot convert 'std::_Mem_fn<int (app::*)(Json::Value&)>' to 'cb' {aka 'int (*)(Json::Value&)'}。为了能够使代码尽可能通用,以便我也可以使用其他回调调用 websocket::listen();,我不想更改 cb typedef。 我也不能使 app::callback 静态,因为它需要 this->db。处理这个问题的最佳方法是什么?

有两个问题:

  • std::mem_fn(&app::callback)app 的实例作为第一个参数。
  • 最惯用的替代方法是使用捕获 lambda,例如
    [this] (Json::Value& json) { return callback(json); }
    
    但是 ,这使得实现用于存储和动态调度它们的通用容器变得极其困难。

一种可能的方法是修改您的 websocket 界面并接受一个可选的 void* 上下文参数,如下所示:

using cb = int(*)(Json::Value &json, void* ctx);

static void websocket::listen(cb callback, const char* address, void* ctx = nullptr)
{
    ...
}

int app::callback(Json::Value& json)
{
    return db->insert(json);
}

void app::start()
{
    websocket::listen([] (Json::Value &json, void* ctx) -> int {
        return static_cast<app*>(ctx)->callback(json);
    }, path, this);
}

如果你更喜欢这种擦除的类型安全性,你可以考虑std::any:

using cb = int(*)(Json::Value &json, std::any ctx);

static void websocket::listen(cb callback, const char* address, std::any ctx = {})
{
    ...
}

int app::callback(Json::Value& json)
{
    return db->insert(json);
}

void app::start()
{
    websocket::listen([] (Json::Value &json, const std::any& ctx) -> int {
        return std::any_cast<app*>(ctx)->callback(json);
    }, path, this);
}

std::any_cast will throw a std::bad_any_cast 如果 ctx 为空或存储的指针不是已擦除的类型 app*