Downcasting non-template base class to templated derived class: is it possible?

c++, casting, event-handling, templates

Solution

In general when closing templates, you need to make sure that > are separated by spaces so the compiler doesn't parse them as a right-shift operator.

Here you're trying to static cast a reference to a non-reference, which even if it worked could invoke object slicing. You need to static cast to a derived reference.

bool  equal(const BaseEventHandler& other) const
{
    EventHandler<T,TEvent>& derivedOther = static_cast<EventHandler<T,TEvent>&>(other);
    return derivedOther.getInstance() == this->getInstance() && derivedOther.getCallback()==this->getCallback();
}

Problem

I'm implementing an event system for a game. It uses an event queue, and a data structure to hold all registered event handlers for a given event type. It works fine so far registering handlers, but when it comes to unregistering them (something that will take place when a game object is destroyed, for instance) I'm having a bit of trouble regarding templates and casting. I've defined an EventHandler as some sort of functor, partially based on Szymon Gatner's article on http://www.gamedev.net/reference/programming/features/effeventcpp/ . To be precise, I took the HandlerFunctionBase and MemberFunctionHandler class definitions and came up with: ``` class BaseEventHandler { public: virtual ~BaseEventHandler(){} void handleEvent(const EventPtr evt) { invoke(evt); } private: virtual void invoke(const EventPtr evt)=0; }; template <class T, class TEvent> class EventHandler: public BaseEventHandler { public: typedef void (T::*TMemberFunction)(boost::shared_ptr<TEvent>); typedef boost::shared_ptr<T> TPtr; typedef boost::shared_ptr<TEvent> TEventPtr; EventHandler(TPtr instance, TMemberFunction memFn) : mInstance(instance), mCallback(memFn) {} void invoke(const EventPtr evt) { (mInstance.get()->*mCallback)(boost::dynamic_pointer_cast<TEvent>(evt)); } TPtr getInstance() const{return mInstance;} TMemberFunction getCallback() const{return mCallback;} private: TPtr mInstance; TMemberFunction mCallback; }; ``` Then the initial implementation for the unregisterHandler() method on the EventManager class I've thought of would go like this: ``` // EventHandlerPtr is a boost::shared_ptr<BaseEventHandler>. // mEventHandlers is an STL map indexed by TEventType, where the values are a std::list<EventHandlerPtr> void EventManager::unregisterHandler(EventHandlerPtr hdl,TEventType evtType) { if (!mEventHandlers.empty() && mEventHandlers.count(evtType)) { mEventHandlers[evtType].remove(hdl); //remove entry if there are no more handlers subscribed for the event type if (mEventHandlers[evtType].size()==0) mEventHandlers.erase(evtType); } } ``` To make "remove" work here I thought of overloading the == operator for BaseEventHandler, and then using a virtual method to perform the actual comparison... ``` bool BaseEventHandler::operator== (const BaseEventHandler& other) const { if (typeid(*this)!=typeid(other)) return false; return equal(other); } ``` and, on the template class EventHandler, implement the abstract method 'equal' like this: ``` bool equal(const BaseEventHandler& other) const { EventHandler<T,TEvent> derivedOther = static_cast<EventHandler<T,TEvent>>(other); return derivedOther.getInstance() == this->getInstance() && derivedOther.getCallback()==this->getCallback(); } ``` Of course, I'm getting a compile error on the static_cast line. I'm not even sure that it is possible at all to do that cast (not necessarily using static_cast). Is there a way to perform it, or at least some workaround that does the trick? Thanks in advance =)

Original source