views:

246

answers:

2

So I'm working on this event management class. I'm storing a list of pointers to member functions of the signature void (Event*) where Event is just a struct that stores some random data at the moment.

typedef boost::function<void(Event*)> Callback;
typedef vector<Callback> CallbackList;

class EventManager
{
public:
   template<typename T>
   void RegisterEventHandler(const std::string& type, void (T::*handler)(Event*), T* obj)
   {
      mCallbackList[type].push_back(boost::bind(handler, obj, _1));
   }

   void DispatchEvent(const std::string& type, Event* evt)
   {
      for(CallbackList::iterator it = mCallbackList[type].begin(); it != mCallbackList[type].end(); ++it)
      {
         Callback callback = (*it);
         callback(evt);
      }   
   }
private:
   hash_map<std::string, CallbackList> mCallbackList;
};

I'm wondering, if it's possible for me to derive different versions of Event, and pass pointers to those member functions into this class? Currently I'm trying this.

class MouseEvent : public Event
{
public:
   int testMouseData1;
   int testMouseData2;
   int testMouseData3;
};

class HelloWorld 
{
public:
   void Display(MouseEvent* evt)
   {
      cout << "Hello, world!" << endl;
   }
};


int main(void)
{
   MouseEvent* evt = new MouseEvent();

   HelloWorld* world = new HelloWorld();
   eventManager->RegisterEventHandler("testType", &HelloWorld::Display, world);

   return 0;
}

This gives me the following error in XCode.

error: no matching function for call to 'EventManager::RegisterEventHandler(const char [9], void (HelloWorld::*)(MouseEvent*), HelloWorld*&)'

Do you know how I can safely pass in a pointer that's expecting a derived class in its function signature? Thanks.

+1  A: 

If your prototype expects "Event" type then you need to make sure the void Display(MouseEvent* evt) function is accepting the "Event" type. So change it to void Display(Event *evt) Then inside the call you can typecast it back to a MouseEvent, assuming that the caller passed an actual MouseEvent, referenced as an "Event".

Secondly, I believe you may have some other issues with the way you are calling RegisterEventHandler since it is in a template but you are not specifying the template type.

Harley Green
@Harley - Template functions have type inference, so I'd say the way he calls RegisterEventHandler is OK
Manuel
function template parameters can be inferred from function arguments, nevertheless explicitly specifying template type would help op determine why instantiation failed
aaa
Agreed, just trying to eliminate all the variables here. Pretty sure the main point @Morgan needs to look at here is the "Event" type vs "MouseEvent".
Harley Green
A: 

So I found a solution that seems to be working for me, but I'm not sure if it's entirely safe to do. I changed the RegisterEventHandler method to cast all of the function pointers that I send in to the same type...

 template<typename T1, typename T2>
   void RegisterEventHandler(const String& type, T1 handler, T2* obj)
   {
      void (T2::*evtHandler)(Event*) = (void (T2::*)(Event*)) (handler);
      mCallbackList[type].push_back(boost::bind(evtHandler, obj, _1));
   }

now it all seems to just work as I originally intended. But I'm pretty new to all this so I'm not entirely sure if this is a safe thing to do. Any thoughts? Thanks

Morgan