Sign in to follow this  
Maarten Baert

Pointer to class member functions without knowing the class type

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this