Pointer to class member functions without knowing the class type

Started by
3 comments, last by pablo24 14 years, 7 months ago
I was wondering whether it would be possible to create pointers to member functions without knowing the class type. Something like this:

void CallMemberFunction(void* instance, void (*memberfunction)(int)) {
	instance->(*memberfunction)(5);
}
Because essentially this is the same as:

void CallMemberFunction(void* instance, void (*memberfunction)(void*,int)) {
	(*memberfunction)(instance,5);
}
I want to use this to create callback functions for my application class, like this:

void MyClass::MyClass {
	
	okbutton = window->CreateButton("OK");
	okbutton->OnPressedCallback(this,OkButtonPressed);
	
	cancelbutton = window->CreateButton("Cancel");
	cancelbutton->OnPressedCallback(this,CancelButtonPressed);
	
	nameedit = window->CreateEdit("Untitled");
	nameedit->OnChangeCallback(this,NameEditChanged);
	
}
void MyClass::OkButtonPressed() {
	// do something
}
void MyClass::CancelButtonPressed() {
	// do something else
}
void MyClass::NameEditChanged() {
	// update something
}
Is this possible? Or do I have to use some hack to do this? I could use static callback functions of course, but it would be easier to use normal member functions if it's not too difficult.
Advertisement
zymurgy
More portable way is using templates.

A good place to start is a reflection library here.

The key idea is to have a set of "invoker" functions all with the same prototype - void Invoker(FUNC_PTR func, void** args, void* result). FUNC_PTR here is a special type that holds an actual function pointer, you cannot use a simple void* because function pointer can be bigger in case of complex class hierarchies.

Invoker is responsible to cast and unpack all parameters and make the legal Cpp call. And because all invokers have the same prototype they can be stored uniformly.

Here's the example of such invokers for function and class method with two parameters (not counting implicit 'this' in method case):

#define MAKE_FPTR()		FT mptr = FunctionCast<FT>(fptr)#define UNPCK_ARG(T, ARG)	(*(T*)args[ARG])#define UNPCK_RET()		(*(RT*)res)#define UNPCK_INS(T, ARG)	(*(T**)args[ARG])#define UNPCK_INS_CALL(T, ARG, MPTR) (UNPCK_INS(C, ARG)->*MPTR)template<class FT, class A1, class A2, class RT>void InvokeFunction(FUNC_PTR fptr, void** args, void* res){ UNPCK_RET() = FunctionCast<FT>(fptr)(UNPCK_ARG(A1, 0), UNPCK_ARG(A2, 1)); }template<class FT, class C, class A1, class A2, class RT>void InvokeMethod(FUNC_PTR fptr, void** args, void* res){	MAKE_FPTR();	UNPCK_RET() = UNPCK_INS_CALL(C, 0, mptr)(UNPCK_ARG(A1, 1), UNPCK_ARG(A2, 2));}


I've generated all my invokers with simple Python script :)

Invoker creation can be simplified by another set of functions which allow template argument deduction (also generated). You can also add a runtime argument validation.

This is not easy approach, but it allows to handle such complex cases like reference return types etc.
I would advise you to use boost::signals or signals2 in conjunction with boost::bind (which allows you to bind function arguments with functions). I think they solve exactly what you want to achieve. I'm doing the same thing in my little win32/gui wrapper and so far it works great.
Quote:Original post by SiS-Shadowman
I would advise you to use boost::signals or signals2 in conjunction with boost::bind (which allows you to bind function arguments with functions). I think they solve exactly what you want to achieve. I'm doing the same thing in my little win32/gui wrapper and so far it works great.


this, or you could use one of the fastdelegate libs, or wait for c++0x and this will be supported:

std::function f = [this]() { // code here};


you can already try it out with the VS10 beta 1

This topic is closed to new replies.

Advertisement