C++: passing the template callback method into the other method: cannot convert ‘unresolved overloaded function type to pointer
You must qualify the name of a non-static member with the class name explicitly when constructing a pointer to member.
(emphasis mine)
- If the operand is a qualified name of a non-static member, e.g.
&C::member
, the result is a prvalue pointer to member function or
pointer to data member of type T in class C. Note that neither&member
norC::member
nor even&(C::member)
may be used to initialize a
pointer to member.
E.g.
store_subflow_bunch_on_open(
handle(response_msg.file_id), response_msg.msg_id,
static_cast<CIFS_RESOURCE_TYPE>(parm_open2_rsp->resource_type),
&smb1_subdecoder::send_subflow_premature_end_msg<ntdec_cifs_close_request>,
// ^^^^^^^^^^^^^^^^^
&smb1_subdecoder::send_subflow_premature_end_msg<ntdec_cifs_close_response>);
// ^^^^^^^^^^^^^^^^^
Using a C++ class member function (cannot be static) as a C callback function
It is not possible, at least with that handler_t
signature.
While you can create a free function on your .cpp to wrap the member call, you need a pointer to the Foo
instance:
void my_wrap(int foo, void* bar) {
Foo* some_foo_instance = ...;
some_foo_instance->handler(foo, bar);
}
int main(int argc, char **argv) {
set_handler(&my_wrap);
}
You need some void* to pass the Foo
instance as a handler attribute:
// Header
typedef void (*handler_t)(int foo, void *bar, void* arg1);
void set_handler(handler_t h, void* arg1);
// Impl.
void set_handler(handler_t h, void* arg1) {
handler_ = h;
handler_arg1_ = arg1;
}
// cpp
void my_wrap(int foo, void* bar, void* arg1) {
Foo* some_foo_instance = static_cast<Foo*>(arg1);
some_foo_instance->handler(foo, bar);
}
// main
int main(int argc, char **argv) {
Foo some_concrete_instance;
set_handler(&my_wrap, static_cast<void*>(&some_concrete_instance));
}
C++ Member function as a callback
There are two problems:
std::mem_fn(&app::callback)
takes an instance ofapp
as the first parameter.- The most idiomatic alternative would be to use a capturing lambda such as
but these cannot be converted to function pointers, which makes implementing generic containers for storing and dynamically dispatching to them extremely difficult to do.[this] (Json::Value& json) { return callback(json); }
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*
.
Passing a member function as standard function callback
Member functions take *this
pointer as a first parameter, so your function signature is actually:
void(HouseKeeper*, char*, uint8_t*, unsigned int)
While std::function in library setCallback function takes:
std::function<void(char*, unsigned char*, unsigned int)>.
You have to change your uint8_t*
to unsigned char*
in your callback second parameter (thanks Daniel H), and also get rid of implicit *this
.
You can use std::bind to bind
*this
pointer to match setCallback() signature:std::function<void(char*, uint8_t*, unsigned int)> yourFunction = std::bind(&HouseKeeper::callback, this, _1, _2, _3);
library.setCallback(yourFunction);Or wrap your call in lambda function:
std::function<void(char*, uint8_t*, unsigned int)> yourFunction = [=](char* topic, uint8_t* payload, unsigned int length) {
this->callback(topic, payload, length);
}
library.setCallback(yourFunction);
Conversion from class member function to C-like function pointer
i would like to pass directly to cURL a member function of a given class, using something like std::bind or std::mem_fn, but the result of these templates cannot be assigned to a C function pointer, as required in my case. Is there an elegant solution to this issue?
The solution you already have, using a static function (or a free function), is the only option.
How to use a C++ member function as the callback function for a C framework
Does callback function need to be declared under extern "C"?
NO. extern "C" is necessary only when you are calling a C++ function directly, without the use of function pointers, from C. If function pointers are used, extern "C" is not required.
Can I use non-static member functions as a callback?
NO. Non-static member functions of class A have an implicit first parameter corresponding to this pointer.
Can I use static member functions as a callback?
YES, as long as signature matches with that of the callback.
Does it matter if the function is a template function or not?
NO, template function can be used as callbacks as long as the signature of the instantiated template matches with the callback.
Using a C++ class member function as a C callback function
You can do that if the member function is static.
Non-static member functions of class A have an implicit first parameter of type class A*
which corresponds to this pointer. That's why you could only register them if the signature of the callback also had the first parameter of class A*
type.
Callback to a member function
You cannot use a non-static member function as a callback parameter that expects a regular function, because their signatures are incompatible:
- A non-member or a static member function takes only the parameters in its signature
- A non-static member function takes an additional "hidden" parameter for the object on which it is called.
The common workaround for this is possible only if the library that performs a callback lets you pass custom parameters with the callback registration. This is usually done with a void*
pointer, which you pass to the library when you register the callback, and then the library passes it back to you when it calls back the callback function.
Here is how:
// This is the static function that you register for your callback
static void staticContinueAfterDESCRIBE(RTSPClient *client, ...) {
static_cast<MyRTSPClient*>(client)-> continueAfterDESCRIBE(client, ...);
}
Now that the function is static, you have no problem registering it as a callback. Once the function gets the control, it casts client
to your MyRTSPClient*
class, and performs the non-static callback.
How can I pass a class member function as a callback?
That doesn't work because a member function pointer cannot be handled like a normal function pointer, because it expects a "this" object argument.
Instead you can pass a static member function as follows, which are like normal non-member functions in this regard:
m_cRedundencyManager->Init(&CLoggersInfra::Callback, this);
The function can be defined as follows
static void Callback(int other_arg, void * this_pointer) {
CLoggersInfra * self = static_cast<CLoggersInfra*>(this_pointer);
self->RedundencyManagerCallBack(other_arg);
}
Related Topics
Std::Thread Is Not a Member of Namespace Std Using Eclipse Kepler Mingw
How to Determine If a C++ Object Has Been Deallocated
Clean C++ Granular Friend Equivalent? (Answer: Attorney-Client Idiom)
How to Play or Open *.Mp3 or *.Wav Sound File in C++ Program
What Happens If 'Throw' Fails to Allocate Memory for Exception Object
How to Programmatically Create a Shortcut Using Win32
Why Was the Space Character Not Chosen for C++14 Digit Separators
C++ Template Functions Overload Resolution
Designated Initializers in C++20
How to Emulate _Mm256_Loadu_Epi32 with Gcc or Clang
How to Convert from Int to Char*
Why Can a T* Be Passed in Register, But a Unique_Ptr<T> Cannot
How Is Static Variable Initialization Implemented by the Compiler
Visual Studio 2015 Run-Time Dependencies or How to Get Rid of Universal Crt