Creating a decorateable effective event handling type in c++
This has been really killing me for the last couple of days now. I effectively have something like what Szymon Gatner explained in his fantastic article, found here. (Check out the EventHandler class in the demo code there)
This is one of the few articles I've found on the web that do a good job explaining how to create a type with an expandable interface. I particularly liked the resulting usage syntax, quite simple to understand.
However, I have one more thing I want to do with this type, and that is to allow it to be decorated. Now, to decorate it with extra data members is one thing, but I'd like to allow the decoration to expand the interface as well, with the function EventHandler::handleEvent being the only method required to be exposed publicly.
Now, unfortunately, the EventHandler::registerEventFunc method is templated. This means that I cannot define it as a virtual method in some even more base class that EventHandler would inherit from, such as HandlerBase.
My question is whether or not someone has any good ideas on how to solve the problem (making EventHandler decorateable).
I've tried creating methods
1)
void registerEventFunc(boost::function<void()> * _memFn);
and 2)
void registerEventFunc(boost::function<void(*SomeDerivedEvent*)> * _memFn);
and 3)
void registerEventFunc(boost::function<void(EventBase*)> * __memFn);
For 1, if I do that, I lose the typeid of the callback's class Event derived argument type. For 2, I'd have to overload the function for as many Ev开发者_如何学Goent callbacks this class plans on registering For 3, Polymorphism does't work in template parameters ( do correct me if I'm wrong ).
The closest I've come to allowing the function to be made virtual is with 1, , but I have to bind the argument to the boost::function at the boost::function object's creation and can't use lambda on it later in the body of EventHandler::handleEvent.
class FooEvent : public Event
{
public:
FooEvent(int _val) : Event(), val(_val){}
int val;
};
class MyHandler : public EventHandler
{
public:
MyHandler()
{
registerEventFunc(new boost::function<void()>(boost::bind(boost::mem_fn(&MyHandler::onEvent),this, new FooEvent(5))));
}
void onEvent(const FooEvent * _event)
{
cout << _event->val << endl;
}
};
Ultimately, I don't think that works though ( it can't figure out that whole typeInfo business to create the key for the map lookup)
Any ideas would be greatly appreciated!
If I'm going about this the wrong way, I would be grateful for the mention of alternatives. The goal in the end of course is to have a decoratable type that can expand it's public interface easily as well as it's data members. I thought Szymon's stuff was a good starting point since it seemed to have the 2nd half done already.
Thank you ahead of time for any assistance.
Perhaps one option would be to create a templated public function that preserves type information, plus a virtual protected function for actually registering the handler. That is:
class event_source {
protected:
struct EventAdapter {
virtual void invoke(EventBase *) = 0;
virtual ~EventAdapter() { }
};
template<typename EventParam>
struct EventAdapterInst : public EventAdapter {
boost::function<void(const EventParam &)> func_;
EventAdapterInst(const boost::function<void(const EventParam &)> &func)
: func_(func)
{ }
virtual void invoke(EventBase *eb) {
EventParam *param = dynamic_cast<EventParam *>(eb);
assert(param);
func_(*param);
}
};
virtual void register_handler(std::type_info param_type, EventAdapter *ea);
public:
template<typename EventParam>
void register_handler(const boost::function<const EventParam &> &handler)
{
register_handler(typeid(EventParam), new EventAdapterInst(handler));
}
};
Derived classes can override the virtual register_handler
to do whatever they like without breaking the type inference properties of the template function.
精彩评论