// typedef from library that I cannot change
typedef int (*mg_request_handler)(mg_connection *conn, void *cbdata);
// this free function is for testing
int get_handler_free(struct mg_connection* conn, void* cbdata) {
//...
}
// this member function is what I want to use
int HttpServer::get_handler_member(struct mg_connection* conn, void* cbdata) {
//...
}
// inside this member function, the callback param is needed
void HttpServer::start() {
//...
// this way doesn't work
mg_request_handler get_handler = std::bind(&HttpServer::get_handler_member, this);
mg_set_request_handler(ctx_, "/get", get_handler, nullptr);
// this way works well
mg_request_handler get_handler = &get_handler_free;
mg_set_request_handler(ctx_, "/get", get_handler, nullptr);
//...
}

- 400,186
- 35
- 402
- 621

- 4,196
- 1
- 38
- 65
-
You really can't use member functions as pointers to non-member functions, no matter how you spin it. The only workaround is to use a `static` member function that gets a pointer to the object as an argument (or as a member of a structure passed as argument) and then call the non-static member function. – Some programmer dude Oct 15 '18 at 15:18
-
I think the third parameter is a ”user data” pointer where you can pass a pointer to your object. – molbdnilo Oct 15 '18 at 15:52
1 Answers
It is not possible to have a (non-member-) function pointer to a non-static member function. It is also not possible to point a function pointer to a bound function.
Notice how the free function type has an argument void *cbdata
. You haven't shown the documentation of the API that you use, but I would be willing to bet that the API follows a common idiom, and the third argument of mg_set_request_handler
is also void *cbdata
. If my assumption is correct, the same pointer that was passed to registration, will be passed to the handler later. It's purpose is to pass data - such as your HttpServer
instance into the callback.
For example:
mg_set_request_handler(ctx_, "/get", [](mg_connection *conn, void *cbdata) {
assert(cbdata);
HttpServer& server = *static_cast<HttpServer*>(cbdata);
server.get_handler_member(conn, cbdata);
}, this);
If get_handler_member
has non-public access, then you'll need to use a static member function instead of the lambda that I used in my example. Also, the cbdata
argument of get_handler_member
is now probably useless and can be removed.
Do remember to keep the HttpServer
instance alive as long as the handler is registered.
Also, to re-iterate: This relies on my assumption about the API that you've shown. Consult the documentation carefully.

- 232,697
- 12
- 197
- 326
-
I'd worry about the lifetime of that lambda. But otherwise, I agree with your "general" approach here. – Kevin Anderson Oct 15 '18 at 16:01
-
1@KevinAnderson No need to worry. The lambda doesn't capture anything. – eerorika Oct 15 '18 at 16:05
-
@duong_dajgja A leftover from an earlier version which was unnecessarily complex. I've fixed it now. – eerorika Oct 15 '18 at 16:08
-
oh this way I can just bypass `cbdata` in `server.get_handler_member(conn, cbdata);` -> `server.get_handler_member(conn, nullptr);` right? – duong_dajgja Oct 15 '18 at 16:09
-
@duong_dajgja Why not remove the argument from the member function completely? You *could* pass more data than just `this` in the pointer, but a better alternative is probably to keep any data as members of `HttpServer`. – eerorika Oct 15 '18 at 16:12
-
I can make `get_handler_free` a friend function of `HttpServer` class then it can freely access the private `get_handler_member`. Interesting! – duong_dajgja Oct 15 '18 at 16:28