a quick question regarding extending a class with boost::function

Hello all: I am working on a mud engine (essentially a game engine), and I had a quick question. I have an event class (yes, I know about boost::signal, but I don't want to go back and it doesn't support delayed events). I would like to set up my event class so that it will take a function object as it's callback, which allows someone extending the engine to add their own content to use global functions, member functions, lambdas, etc etc. Now, here is my problem, and this may be more of a c++ question than a boost question; I'm not really sure. Right now, every time an event gets called, I pass in the object that called it, as well as an EventArgs pointer. So an event callback function might look like this: void OnMouseDown(Object* obj, OnMouseDownArgs* args); Now, it might be useful to have the x and y coordenates where the OnMouseDown event was called, which means I end up doing something like: class OnMouseDownArgs:public EventArgs { public: int x, y; }; which essentially means that for every new type of event, I have to declare an EventArgs class for that. So here was my idea; I thought it would be kind of cool to do something like: Event* OnMouseDown<int, int> = new Event<int, int>(); which leads me to a question. given that template, how would I define a function object with those arguments? better yet, how would I accept an arbitrary number of arguments to the template, then take those arguments and create a boost::function object with them, as well as extend the .Call method to take the arguments I passed in? So in summary, I am trying to extend the boost::function object to accept a set of arguments passed in through a template when the Event object was created, as well as extend the Call method on the Event object to take the two ints as in the MouseDownEvent as arguments. Thanks, Ty

AMDG On 04/06/2011 09:22 AM, Littlefield, Tyler wrote:
Hello all: I am working on a mud engine (essentially a game engine), and I had a quick question. I have an event class (yes, I know about boost::signal, but I don't want to go back and it doesn't support delayed events). I would like to set up my event class so that it will take a function object as it's callback, which allows someone extending the engine to add their own content to use global functions, member functions, lambdas, etc etc.
Now, here is my problem, and this may be more of a c++ question than a boost question; I'm not really sure.
Right now, every time an event gets called, I pass in the object that called it, as well as an EventArgs pointer. So an event callback function might look like this: void OnMouseDown(Object* obj, OnMouseDownArgs* args); Now, it might be useful to have the x and y coordenates where the OnMouseDown event was called, which means I end up doing something like: class OnMouseDownArgs:public EventArgs { public: int x, y; }; which essentially means that for every new type of event, I have to declare an EventArgs class for that. So here was my idea; I thought it would be kind of cool to do something like: Event* OnMouseDown<int, int> = new Event<int, int>(); which leads me to a question. given that template, how would I define a function object with those arguments? better yet, how would I accept an arbitrary number of arguments to the template, then take those arguments and create a boost::function object with them, as well as extend the .Call method to take the arguments I passed in? So in summary, I am trying to extend the boost::function object to accept a set of arguments passed in through a template when the Event object was created, as well as extend the Call method on the Event object to take the two ints as in the MouseDownEvent as arguments.
So, first of all, I assume that you can't make the Event handler a template? So, what you'd like to be able to do is something like this: EventHandler handler; Object* o; struct f { void operator()(Object* caller, int x, int y) const; }; handler.set<int, int>(f()); handler.call(o, 1, 2); Am I understanding you correctly? It's impossible to make this perfectly type-safe at compile time, since you can't tie the call directly to the function object. However, it can be implemented with a runtime type check: (warning untested code) template<class T, class F> struct function_adapter { void operator()(Object* o, const boost::any& arg) { return f(o, boost::any_cast<T>(arg)); } F f; }; class EventHandler { public: template<class T, class F> void set(F f) { function_adapter<T, F> impl = { f }; f_ = impl; } template<class T> void call(Object* o, const T& arg) { f_(o, arg); } private: boost::function<void(Object*, const boost::any&)> f_; }; This solution only allows a single argument, but we can combine multiple arguments into one fairly easily: EventHandler handler; handler.set<boost::tuple<int, int> >(boost::fusion::make_fused(f())); handler.call(o, boost::make_tuple(1, 2)); In Christ, Steven Watanabe

Steven: Thanks for your response and your help; for the last thread as well, since I forgot to thank you for that one, and your informatiuon there helped. I think that was pretty much what I wanted. I"ll have to learn a bit about fusion and any, but it seems solid. Thanks again. On 4/6/2011 11:58 AM, Steven Watanabe wrote:
AMDG
On 04/06/2011 09:22 AM, Littlefield, Tyler wrote:
Hello all: I am working on a mud engine (essentially a game engine), and I had a quick question. I have an event class (yes, I know about boost::signal, but I don't want to go back and it doesn't support delayed events). I would like to set up my event class so that it will take a function object as it's callback, which allows someone extending the engine to add their own content to use global functions, member functions, lambdas, etc etc.
Now, here is my problem, and this may be more of a c++ question than a boost question; I'm not really sure.
Right now, every time an event gets called, I pass in the object that called it, as well as an EventArgs pointer. So an event callback function might look like this: void OnMouseDown(Object* obj, OnMouseDownArgs* args); Now, it might be useful to have the x and y coordenates where the OnMouseDown event was called, which means I end up doing something like: class OnMouseDownArgs:public EventArgs { public: int x, y; }; which essentially means that for every new type of event, I have to declare an EventArgs class for that. So here was my idea; I thought it would be kind of cool to do something like: Event* OnMouseDown<int, int> = new Event<int, int>(); which leads me to a question. given that template, how would I define a function object with those arguments? better yet, how would I accept an arbitrary number of arguments to the template, then take those arguments and create a boost::function object with them, as well as extend the .Call method to take the arguments I passed in? So in summary, I am trying to extend the boost::function object to accept a set of arguments passed in through a template when the Event object was created, as well as extend the Call method on the Event object to take the two ints as in the MouseDownEvent as arguments.
So, first of all, I assume that you can't make the Event handler a template? So, what you'd like to be able to do is something like this:
EventHandler handler; Object* o;
struct f { void operator()(Object* caller, int x, int y) const; };
handler.set<int, int>(f()); handler.call(o, 1, 2);
Am I understanding you correctly?
It's impossible to make this perfectly type-safe at compile time, since you can't tie the call directly to the function object. However, it can be implemented with a runtime type check: (warning untested code)
template<class T, class F> struct function_adapter { void operator()(Object* o, const boost::any& arg) { return f(o, boost::any_cast<T>(arg)); } F f; };
class EventHandler { public: template<class T, class F> void set(F f) { function_adapter<T, F> impl = { f }; f_ = impl; } template<class T> void call(Object* o, const T& arg) { f_(o, arg); } private: boost::function<void(Object*, const boost::any&)> f_; };
This solution only allows a single argument, but we can combine multiple arguments into one fairly easily:
EventHandler handler; handler.set<boost::tuple<int, int> >(boost::fusion::make_fused(f())); handler.call(o, boost::make_tuple(1, 2));
In Christ, Steven Watanabe _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
-- Thanks, Ty
participants (2)
-
Littlefield, Tyler
-
Steven Watanabe