How to Pass a Member Function Where a Free Function Is Expected

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.

  1. You are calling fun1 and fun2. Since their return type is void, 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.

  2. 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



Leave a reply



Submit