2

I am using a library that expects a function pointer for a callback function but I would like to pass a member function to it.

The way to do this seems to be by using std::bind and passing the target() as a parameter to the function expecting the function pointer, but I must be doing something wrong.

#include <iostream> #include <functional> using namespace std; typedef void(__stdcall* ClassicFuncPtr)(int a, double b); void CallMyFunc(ClassicFuncPtr f) { f(1, 2.0); } class MyClass { public: void Test() { function<void(int, double)> f = bind(&MyClass::MemberFunc, this, placeholders::_1, placeholders::_2); CallMyFunc(*f.target<ClassicFuncPtr>()); // not working, i don't know why... } private: void MemberFunc(int a, double b) { cout << "a=" << a << ", b=" << b << '\n'; } }; int main() { MyClass c; c.Test(); } 

The target() returns a nullpointer.

2
  • Make MemberFunction a static member function, and pass a pointer to it directly? Unless it's really using other members of the object, because then there's really no way to do it using the information you have provided. Commented Jun 29, 2021 at 8:29
  • 1
    The MemberFunction expects a this pointer. How are you going to pass it, even in principle? Commented Jun 29, 2021 at 8:31

2 Answers 2

1

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); 
Sign up to request clarification or add additional context in comments.

Comments

1

It's not possible to do that.The type of pointer-to-member-function is different from pointer-to-function. For example:

  • It will be int (*)(int,double) if an ordinary function.
  • It will be int (MyClass ::*)(int,dobule) if a non-static member function of class MyClass

Note: In case that it’s a static member function, its type is the same as if it was an ordinary function int (*)(int,double).

In order to make it work somehow with the non-static member function. It also needs this pointer. Thus, you can rewrite the function as following

typedef void(MyClass::*ClassicFuncPtr)(int a, double b); void CallMyFunc(MyClass* t, ClassicFuncPtr f) { (t->*f)(1, 2.0); } 

1 Comment

OP wrote that they uses a library. Changing a callback type might be impossible then.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.