How can I pass a member function where a free function is expected?
There isn't anything wrong with using function pointers. However, pointers to non-static member functions are not like normal function pointers: member functions need to be called on an object which is passed as an implicit argument to the function. The signature of your member function above is, thus
void (aClass::*)(int, int)
rather than the type you try to use
void (*)(int, int)
One approach could consist in making the member function static
in which case it doesn't require any object to be called on and you can use it with the type void (*)(int, int)
.
If you need to access any non-static member of your class and you need to stick with function pointers, e.g., because the function is part of a C interface, your best option is to always pass a void*
to your function taking function pointers and call your member through a forwarding function which obtains an object from the void*
and then calls the member function.
In a proper C++ interface you might want to have a look at having your function take templated argument for function objects to use arbitrary class types. If using a templated interface is undesirable you should use something like std::function<void(int, int)>
: you can create a suitably callable function object for these, e.g., using std::bind()
.
The type-safe approaches using a template argument for the class type or a suitable std::function<...>
are preferable than using a void*
interface as they remove the potential for errors due to a cast to the wrong type.
To clarify how to use a function pointer to call a member function, here is an example:
// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
fptr(context, 17, 42);
}
void non_member(void*, int i0, int i1) {
std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
}
struct foo {
void member(int i0, int i1) {
std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
}
};
void forwarder(void* context, int i0, int i1) {
static_cast<foo*>(context)->member(i0, i1);
}
int main() {
somefunction(&non_member, nullptr);
foo object;
somefunction(&forwarder, &object);
}
How do I pass a member function to a function that expects a function pointer?
The problem here is that a member function expects a "hidden" first argument that is a this
pointer. Loosely speaking, a member function
void Func(int a, double b);
is equivalent to a free function
void Func(MyClass* this, int a, double b);
There is no way to pass a this
pointer via ClassicFuncPtr
, and std::function
tricks won't help you here. target()
doesn't do any magic, it just returns a pointer to the stored function if types match, and in your code they don't, that's why you get a null pointer. std::bind
returns a functional object (that stores this
inside), but a functional object is quite distinct from a function pointer and can't be converted into one.
Given that you can't change the callback type, there is a pretty ugly and fragile work-around that uses a static
variable to store the value of this
pointer. It should give you the idea of how to make it work, at least in principle.
class MyClass {
public:
void Test() {
thisPtr = this;
CallMyFunc(MemberFuncInvoker);
}
private:
inline static MyClass* thisPtr;
static void MemberFuncInvoker(int a, double b) {
thisPtr->MemberFunc(a, b);
}
void MemberFunc(int a, double b) {
std::cout << "a = " << a << ", b = " << b << '\n';
}
};
Note that static
member functions don't expect a hidden this
argument and behave like free functions in this respect (due to the absence of this
argument, you can't access non-static
data members inside a static
member function).
Demo
Typically, callbacks are accompanied with a void*
-like parameter that can be used to pass a this
pointer. For example, theEnumWindows
function from WinAPI has the signature
BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);
That lParam
is passed to a callback
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);
Then, inside a free (or static
) callback function you could do:
reinterpret_cast<MyClass*>(lParam)->MyMemberFunction(hwnd);
Callback member function from API taking a free function with no arguments
Your problem is that the callback type
typedef void (CALLBACK *EventCallback)();
does not have any user-provided data pointer. This is customary for the exact reason that users often need it.
And just for completeness,
Is there any way to cast that member function to a non-member function
No, they're fundamentally different, because non-static member functions must be called with an implicit this
pointer, and there's nowhere to store that in a regular function pointer. That's exactly what we'd use the user-provided pointer argument for if the API had one.
Also I don't want to declare My_class::using_API and My_class::API as static member.
How about if we generate another static
for each distinct registration? We can automate it by using lambda type uniqueness:
template <typename Lambda>
class TrampolineWrapper
{
inline static std::optional<Lambda> dest_; // optional so we can defer initialization
public:
TrampolineWrapper(some_API *api, Lambda &&lambda)
{
// store your _stateful_ functor into a unique static
dest_.emplace( std::move(lambda) );
// register a unique _stateless_ lambda (convertible to free function)
api->EnableInterrupt(
[](){
(*TrampolineWrapper<Lambda>::dest_)();
},
nullptr);
}
};
// handy type-deducing function
template <typename Lambda>
TrampolineWrapper<Lambda> wrap(some_API *api, Lambda &&lambda)
{
return {api, std::move(lambda)};
}
and use it like
class My_class
{
some_API API;
void my_func() { cout << "This is my_func!\n" }
public:
void using_api()
{
auto wrapper = wrap(&API, [this](){ my_func(); });
// stateful lambda ^^^^
// not directly convertible to a free function
}
};
This depends on the uniqueness of lambda types to work - each lambda you use this with gets a unique static dest_
object of the same type (which may be stateful), and a unique stateless forwarding lambda (which is convertible to a free function for this horrible API).
Note that this is unique only if you have multiple distinct callers registering distinct lambdas. Two calls to My_class::using_api
will still collide (the second will overwrite the first's lambda).
The only other nasty thing is that we're discarding the wrapper once the static is set up ... it'd be much nicer to keep it around so we could use it for unregistering the callback or something. You can do this if you want, but since you cannot know its type outside the scope of your lambda, it'll need to do something dynamic.
How to pass a member function as callback param to a function that expects a `typedef-ed` free function pointer?
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.
How to pass a member function as a parameter to a function that doesn't expect it?
Based on the comments, if you cannot change the signature of foo
to take anything but a raw function pointer... then you'll have to do something like this:
struct XFunc2Wrapper {
static X* x;
static void func2(int v) {
x->func2(v);
}
};
And then just do foo(&XFunc2Wrapper::func2)
once you set XFunc2Wrapper::x
to be your X
. It doesn't have to be nested in a struct, it can just be some global pointer, but nesting helps establish the intent behind the code better.
But this should definitely be last resort after (as per Captain Obvlious) trying to do foo(std::function<void(int)> )
.
How to pass a changing member function through another function?
f1
isn't a method of queue
so your code won't compile. You can have different handling of edit_queue
by passing a lambda instead and calling it:
template <typename Container, typename T>
void edit_queue(std::function<void(Container&, const T&)> func, const T& data)
{
func(queue, data);
}
Then call it with a lambda that calls push_back
or push_front
.
Passing functions as arguments in classes
You can use std::bind to pass member methods.
#include <iostream>
#include <memory>
#include <functional>
void print(std::function<double(double)> f) {
std::cout << f(1) << std::endl;
}
class Obj {
public:
double MyFunction(double x);
void PrintFunction();
};
void Obj::PrintFunction(){
auto t = std::bind(&Obj::MyFunction,this,std::placeholders::_1);
print(t);
}
double Obj::MyFunction(double x) {
return x + 1;
}
int main() {
Obj object;
object.PrintFunction();
}
Passing a function pointer to a member function in C++.Getting error
Let's deal with the two issues in the post.
You are calling
fun1
andfun2
. Since their return type isvoid
, you can't pass their result as something's value. In particular as the value of a function pointer. You also can't obtain their address by using the dot member access operator. Which brings us to the following.Member functions are not like regular functions. You cannot just take their address. Their treatment is special, because member functions can only be called on an object. So there's a special syntax for them, which involves the class they belong to.
Here's how you would do something like what you are after:
class student
{
public:
void fun1() { printf("Fun1\n"); }
void fun2() { printf("Fun2\n"); }
// A function that receives a member function
// as parameter and calls the function
void wrapper(void (student::*fun)())
{
(this->*fun)();
}
};
int main()
{ student s;
s.wrapper(&student::fun1);
s.wrapper(&student::fun2);
return 0;
}
Related Topics
C++0X Has No Semaphores? How to Synchronize Threads
Why How to Use Auto on a Private Type
Embedding Resources in Executable Using Gcc
Does "Int Size = 10;" Yield a Constant Expression
How to Call C++ Function from C
Does C++ Support Variable Length Arrays
What's the Rationale For Null Terminated Strings
Position of Least Significant Bit That Is Set
Why Is There an Injected Class Name
When Is the "Typename" Keyword Necessary
Simple Example of Threading in C++
How to Create a Dynamic Array of Integers
What Is the Usefulness of 'Enable_Shared_From_This'
What Happens If You Call Erase() on a Map Element While Iterating from Begin to End