Reputation: 23
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.
Upvotes: 2
Views: 654
Reputation: 26362
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).
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);
Upvotes: 1
Reputation: 1193
It's not possible to do that.The type of pointer-to-member-function is different from pointer-to-function. For example:
int (*)(int,double)
if an ordinary function.int (MyClass ::*)(int,dobule)
if a non-static member function of class MyClassNote: 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);
}
Upvotes: 1