简体   繁体   中英

C++ Member function as a callback

I'm using a static class called websocket which listens on a websocket (hence the name) and calls a callback function once data is received. I created the following declarations

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

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

I also have a class called app which should contain the callback as a member function, because it is using a member property connecting to the database:

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

I'm calling the websocket::listen() function inside app like this:

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

I get an error saying error: cannot convert 'std::_Mem_fn<int (app::*)(Json::Value&)>' to 'cb' {aka 'int (*)(Json::Value&)'} . To be able to keep the code as generic as possible so that I can call websocket::listen(); with other callbacks as well, I don't want to change the cb typedef. I can also not make app::callback static as it requires this->db . What is the best way to deal with this problem?

There are two problems:

One possible approach is to amend your websocket interface and accept an optional void* context parameter like this:

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);
}

If you prefer more type safety for this erasure, you can consider 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);
}

The std::any_cast will throw a std::bad_any_cast if ctx was empty or storing a pointer that wasn't a type erased app* .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM