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:
std::mem_fn(&app::callback)
takes an instance of app
as the first parameter. [this] (Json::Value& json) { return callback(json); }
but these cannot be converted to function pointers , which makes implementing generic containers for storing and dynamically dispatching to them extremely difficult to do. 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.