pointer to member function as callback function

Started by
2 comments, last by Ninebit 22 years, 2 months ago
Hello Let me define the problem: You have a class with a function that enumerates elements in a list. For each object the function calls the supplied callback function: void CMyClass::EnumObjects(void (*EnumObjectCallback)(OBJECT)) { for each object in objectlist{ EnumObjectCallback(object); } } Now, this would work great for a case where the callbackfunction wouldn''t be in a class void PrintObject(OBJECT); ----- pMyClass->EnumObjects(&PrintObject); But when the callback function is in another class, there will be problem. void CAnotherClass:rintObject(OBJECT); ----- pMyClass->EnumObjects(&pAnotherClass->PrintObject); This is where the problem is. Since I wont be knowing the classtype of the class I cant define the enum finction as EnumObjects(void(CAnotherClass::*EnumObjectCallback)(OBJECT)) that would otherwise be an solution. But then I could liklewise write EnumObjects(CAnotherClass *pAnotherClass), and this would beat the purpouse of the callback. Is anyone sitting on the answer? or questions?
"I could be off endlessly perfecting my 3d engine, but instead I am cursed with the task of actually finishing something, it sucks."
Advertisement
What? Didn''t you understand the question at all?? Or doesn''t anyone know?
"I could be off endlessly perfecting my 3d engine, but instead I am cursed with the task of actually finishing something, it sucks."
Obviously, you must parameterise your EnumObjects() function to generalise on the type of function pointer passed to it. Whenever you hear the words "generalise on type", you should be thinking "templates". The trouble is, on dereferencing and calling a pointer to member function, you need to consider that you must provide it with the correct number and types of parameters, and should cater for the return type. All of these considerations can be generalised using templates, but I''m not going to show you how as I don''t think you need to do this (plus it gets complicated enough to require an entire book to explain).

As a starting point, you could generalise on normal function pointers and member function pointers taking no parms and returning void using a class such as:

  template<typename T>class GeneralisedFunctor{public:	void registerCallback( T t )	{		callback = t;	}	template<class U>	void callMe( U obj ) const	{		(obj.*callback)();	}	void callMe() const	{		callback();	}private:	T callback;};  


So, supposing you had member and non-member functions which looked like this:

  struct Stuff{	void print() { cout << "Stuff::print()" << endl;}	typedef void (Stuff::*callback)();};void print(){	cout << "print()" << endl;}typedef void (*fptr)();  


You could then set this up to register a callback to either member or non-member function type quite easily. Note that users of the GeneralisedFunctor class now have control over what type of function pointer is to be used and, therefore, what class the function pointer is a member of (if any). This is getting nearer to the flexibility you are asking for.

This allows you to easily create a callback on a member or non-member function using something like this:

  int main(){	GeneralisedFunctor<fptr> gf1;	gf1.registerCallback( print );	gf1.callMe();	GeneralisedFunctor<Stuff::callback> gf2;	Stuff s;	gf2.registerCallback( s.print );	gf2.callMe( s );}  


Notice, though, that you have the restriction of only being able to call a function that takes no arguments, and there is no way of retrieving the return value. If you have a limited range of types of function you need to call, it is feasible to simply code a registerCallback() and callMe() overload for each combination of parameters you need. For a truly generic Functor class it is possible to auto-generate the class via template metaprogramming by providing a typelist of every callback type you need to cater for. I won''t go into that as there is no short and simple way of explaining this, and I also think you might be taking the wrong approach.

Hopefully, that gives you some idea of the problems you will come up against in a statically typed language like C++. As a simpler solution, I suggest you look to the STL to see how that can help you. The STL takes the approach of catering only for a small range of Functor types, called unary_function<>() and binary_function<>(). It is relatively trivial to build functors derived from these templated classes and use them seamlessly with STL functions. As a *big* hint, you might like to know the STL provides a for_each() algorithm which does exactly what you are trying to do.

--
1st law of programming: Any given program, when running, is obsolete.
Since it looks like you''re writing a container class, why not use STL''s method of returning an iterator to enumerate that way?

This topic is closed to new replies.

Advertisement