Sign in to follow this  
Nanook

polymorphic parameters with std::function / std::bind

Recommended Posts

I've been working on a event manager and I had a version of this where I use a base non template class and then a templated subscription class to get it working.. but it was a bit hacky so I wanted to use std::function and std::bind, but I'm getting some errors since std::function doesnt seem to like polymorphic parameters.. Is there a way I can make it work? I'm pretty new with std::function and std::bind so might be something easy..

I could use TestEvent on the "typedef std::function<void (Event &event)> HandlerFunc;" line of course, but that kinda defeats my purpose..


The test case should explain what I'm trying to do. (Visual studio compile error below)

[code]

#include <functional>
#include <vector>
#include <iostream>

class Event
{
public:
virtual ~Event(){}
};

class TestEvent : public Event{};

class Manager
{
public:
typedef std::function<void (Event &event)> HandlerFunc;
void AddHandlerFunc(HandlerFunc func)
{
funcs.push_back(func);
}

std::vector<HandlerFunc> funcs;
};

class HandlerBase
{
public:
HandlerBase(Manager *mgr):m_mgr(mgr){}

template<class HandlerT, class EventT>
void Register(void (HandlerT::*eventCallback)(EventT&));
private:
Manager* m_mgr;
};

template<class HandlerT, class EventT>
void HandlerBase::Register( void (HandlerT::*eventCallback)(EventT&) )
{
HandlerT* derivedThisPtr = static_cast<HandlerT*>(this);
m_mgr->AddHandlerFunc(std::bind(eventCallback, derivedThisPtr, std::placeholders::_1));
}

class HandlerDerived : public HandlerBase
{
public:
HandlerDerived(Manager *mgr) : HandlerBase(mgr)
{
Register(&HandlerDerived::HandleTestEvent);
}

void HandleTestEvent(TestEvent &testevent)
{
}
};

int main()
{
Manager mgr;
HandlerDerived handlerInstance(&mgr);
}
[/code]

Error:
[code]

1>------ Build started: Project: Testing, Configuration: Debug Win32 ------
1>Build started 12.04.2011 03:56:04.
1>InitializeBuildStatus:
1> Creating "Debug\Testing.unsuccessfulbuild" because "AlwaysCreate" was specified.
1>ClCompile:
1> main.cpp
1>d:\progs\microsoft visual studio 10.0\vc\include\xxpmfcaller(42): error C2664: 'void (EventT &)' : cannot convert parameter 1 from 'Event' to 'TestEvent &'
1> with
1> [
1> EventT=TestEvent
1> ]
1> d:\progs\microsoft visual studio 10.0\vc\include\xxpmfcaller(52) : see reference to function template instantiation '_Ret std::tr1::_Pmf_caller2<_Ret,_Arg0>::_Call_pmf<_Pmf,_Ty,_Farg1>(volatile const void *,_Pmf,_Farg0 &,_Farg1 &)' being compiled
1> with
1> [
1> _Ret=_Rx,
1> _Arg0=HandlerDerived,
1> _Pmf=void (__thiscall HandlerDerived::* const )(TestEvent &),
1> _Ty=HandlerDerived *,
1> _Farg1=Event,
1> _Farg0=HandlerDerived *
1> ]
1> d:\progs\microsoft visual studio 10.0\vc\include\xxcallpmf(9) : see reference to function template instantiation '_Ret std::tr1::_Pmf_caller2<_Ret,_Arg0>::_Apply_pmf<const _Ty,_Arg,Event>(_Pmf,_Farg0 &,_Farg1 &)' being compiled
1> with
1> [
1> _Ret=_Rx,
1> _Arg0=HandlerDerived,
1> _Ty=void (__thiscall HandlerDerived::* const )(TestEvent &),
1> _Arg=HandlerDerived *,
1> _Pmf=void (__thiscall HandlerDerived::* const )(TestEvent &),
1> _Farg0=HandlerDerived *,
1> _Farg1=Event
1> ]
1> d:\progs\microsoft visual studio 10.0\vc\include\xxbind1(292) : see reference to function template instantiation '_Ret std::tr1::_Callable_pmf<_Ty,_Memty,_Indirect>::_ApplyX<_Ret,_Arg&,Event&>(_Arg0,_Arg1) const' being compiled
1> with
1> [
1> _Ret=_Rx,
1> _Ty=void (__thiscall HandlerDerived::* const )(TestEvent &),
1> _Memty=HandlerDerived,
1> _Indirect=false,
1> _Arg=HandlerDerived *,
1> _Arg0=HandlerDerived *&,
1> _Arg1=Event &
1> ]
1> d:\progs\microsoft visual studio 10.0\vc\include\xxbind0(31) : see reference to function template instantiation '_Ret std::tr1::_Bind2<_Callable,_Arg0,_Arg1>::_ApplyX<_Rx,Event&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&,std::tr1::_Nil&>(_Barg0,_Barg1,_Barg2,_Barg3,_Barg4,_Barg5,_Barg6,_Barg7,_Barg8,_Barg9)' being compiled
1> with
1> [
1> _Ret=_Rx,
1> _Callable=std::tr1::_Callable_pmf<void (__thiscall HandlerDerived::* const )(TestEvent &),HandlerDerived,false>,
1> _Arg0=HandlerDerived *,
1> _Arg1=std::tr1::_Ph<1>,
1> _Barg0=Event &,
1> _Barg1=std::tr1::_Nil &,
1> _Barg2=std::tr1::_Nil &,
1> _Barg3=std::tr1::_Nil &,
1> _Barg4=std::tr1::_Nil &,
1> _Barg5=std::tr1::_Nil &,
1> _Barg6=std::tr1::_Nil &,
1> _Barg7=std::tr1::_Nil &,
1> _Barg8=std::tr1::_Nil &,
1> _Barg9=std::tr1::_Nil &
1> ]
1> d:\progs\microsoft visual studio 10.0\vc\include\xxcallobj(13) : see reference to function template instantiation 'void std::tr1::_Bind_base<_Ret,_BindN>::operator ()<Event&>(_Carg0)' being compiled
1> with
1> [
1> _Ret=void,
1> _BindN=std::tr1::_Bind2<std::tr1::_Callable_pmf<void (__thiscall HandlerDerived::* const )(TestEvent &),HandlerDerived,false>,HandlerDerived *,std::tr1::_Ph<1>>,
1> _Carg0=Event &
1> ]
1> d:\progs\microsoft visual studio 10.0\vc\include\xxfunction(65) : see reference to function template instantiation '_Ret std::tr1::_Callable_obj<_Ty>::_ApplyX<_Rx,Event&>(_Arg0)' being compiled
1> with
1> [
1> _Ret=void,
1> _Ty=std::tr1::_Bind<void,void,std::tr1::_Bind2<std::tr1::_Callable_pmf<void (__thiscall HandlerDerived::* const )(TestEvent &),HandlerDerived,false>,HandlerDerived *,std::tr1::_Ph<1>>>,
1> _Rx=void,
1> _Arg0=Event &
1> ]
1> d:\progs\microsoft visual studio 10.0\vc\include\xxfunction(64) : while compiling class template member function 'void std::tr1::_Impl_no_alloc1<_Callable,_Rx,_Arg0>::_Do_call(_Arg0)'
1> with
1> [
1> _Callable=_MyWrapper,
1> _Rx=void,
1> _Arg0=Event &
1> ]
1> d:\progs\microsoft visual studio 10.0\vc\include\xxfunction(386) : see reference to class template instantiation 'std::tr1::_Impl_no_alloc1<_Callable,_Rx,_Arg0>' being compiled
1> with
1> [
1> _Callable=_MyWrapper,
1> _Rx=void,
1> _Arg0=Event &
1> ]
1> d:\progs\microsoft visual studio 10.0\vc\include\xxfunction(369) : see reference to function template instantiation 'void std::tr1::_Function_impl1<_Ret,_Arg0>::_Reset0o<_Myimpl,_Fty,std::allocator<_Ty>>(_Fty,_Alloc)' being compiled
1> with
1> [
1> _Ret=void,
1> _Arg0=Event &,
1> _Fty=std::tr1::_Bind<void,void,std::tr1::_Bind2<std::tr1::_Callable_pmf<void (__thiscall HandlerDerived::* const )(TestEvent &),HandlerDerived,false>,HandlerDerived *,std::tr1::_Ph<1>>>,
1> _Ty=std::tr1::_Function_impl1<void,Event &>,
1> _Alloc=std::allocator<std::tr1::_Function_impl1<void,Event &>>
1> ]
1> d:\progs\microsoft visual studio 10.0\vc\include\functional(113) : see reference to function template instantiation 'void std::tr1::_Function_impl1<_Ret,_Arg0>::_Reset<_Fx>(_Fty)' being compiled
1> with
1> [
1> _Ret=void,
1> _Arg0=Event &,
1> _Fx=std::tr1::_Bind<void,void,std::tr1::_Bind2<std::tr1::_Callable_pmf<void (__thiscall HandlerDerived::* const )(TestEvent &),HandlerDerived,false>,HandlerDerived *,std::tr1::_Ph<1>>>,
1> _Fty=std::tr1::_Bind<void,void,std::tr1::_Bind2<std::tr1::_Callable_pmf<void (__thiscall HandlerDerived::* const )(TestEvent &),HandlerDerived,false>,HandlerDerived *,std::tr1::_Ph<1>>>
1> ]
1> d:\coding\testing\testing\testing\main.cpp(40) : see reference to function template instantiation 'std::tr1::function<_Fty>::function<std::tr1::_Bind<_Result_type,_Ret,_BindN>>(_Fx)' being compiled
1> with
1> [
1> _Fty=void (Event &),
1> _Result_type=void,
1> _Ret=void,
1> _BindN=std::tr1::_Bind2<std::tr1::_Callable_pmf<void (__thiscall HandlerDerived::* const )(TestEvent &),HandlerDerived,false>,HandlerDerived *,std::tr1::_Ph<1>>,
1> _Fx=std::tr1::_Bind<void,void,std::tr1::_Bind2<std::tr1::_Callable_pmf<void (__thiscall HandlerDerived::* const )(TestEvent &),HandlerDerived,false>,HandlerDerived *,std::tr1::_Ph<1>>>
1> ]
1> d:\coding\testing\testing\testing\main.cpp(48) : see reference to function template instantiation 'void HandlerBase::Register<HandlerDerived,TestEvent>(void (__thiscall HandlerDerived::* )(EventT &))' being compiled
1> with
1> [
1> EventT=TestEvent
1> ]
1>
1>Build FAILED.
1>
1>Time Elapsed 00:00:01.31
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

[/code]

Share this post


Link to post
Share on other sites
Your function takes an Event&, so that's what you need to put in there. Changing the parameter changes the type of the function. You can't override them with derived types and there is no point anyway. In your handler you can only treat the events as Event& and your polymorphism is limited to calling virtual functions or *shudder* downcasting.

Rule of thumb: when you put derived classes into functions that take base classes, you are not supposed to know their exact type, but use the common interface declared in the base class to work with them.

I assume that for different events you want to have a different set of information, so technically you're trying to hide a lot of different event callbacks (having different parameters) behind a common event struct that will hold different parameters. But then what? How would your event handler determine what kind of event it just got when an event handler is supposed to take the base type? (Of course it's possible and most likely involves type enums, dynamic_casts and lots of if and else).

Something that might solve your problem: look at the visitor pattern (aka double dispatch). By playing ping pong, the event object will pass itself to the handler function which allows you to use lots of overloaded handler functions for different types. However this isn't "polymorphism" but plain function overloading. Downside: you need a baseclass for your handlers (typically called Visitor) that has virtual functions (visit()) for each type you want to handle. Classes that will handle events implement that for each event type they can process. Another downside: every single derived event will need to implement a trivial virtual function that does the actual trick: call the handlers visit-function with their actual type instead of their base type. Generally it's called accept(), but I like calling it invite().

When you get an event as base class reference, you call event.invite(handler), invite is implemented as handler.visit(this);

Share this post


Link to post
Share on other sites
Hidden
[font=arial, verdana, tahoma, sans-serif][size=2]Yes I've used the visitor pattern before.. guess I could do that.. this is how I solved it with the non template base class I mentioned in the previous post.. it works, but it feels hacky :P[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]Event.h[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2][font=arial, verdana, tahoma, sans-serif][size=2][code][/size][/font] class Event { public: explicit Event(unsigned id) : m_eventId(id){}
virtual ~Event(){}
unsigned EventId() const { return m_eventId; } private: unsigned m_eventId; };[font=arial, verdana, tahoma, sans-serif][size=2][/code][/size][/font][/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]
[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]EventSubscription.h[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2][code][/size][/font] class HandlerSubscriptionBase { public: virtual ~HandlerSubscriptionBase(){} virtual void CallBack(Event & event) = 0; bool operator==(const HandlerSubscriptionBase& rhs) const { return &rhs == this; } };
template <typename EventHandlerT, typename EventT> class HandlerSubscription : public HandlerSubscriptionBase { public: typedef void (EventHandlerT::*EventCallback)(EventT&);
HandlerSubscription(EventHandlerT& eventHandler, EventCallback callback) : m_eventHandler(eventHandler), m_callback(callback){}
void CallBack(Event& event) { (m_eventHandler.*m_callback)(static_cast<EventT&>(event)); } private: EventHandlerT& m_eventHandler; EventCallback m_callback; };[font=arial, verdana, tahoma, sans-serif][size=2][/code][/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]
[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]EventManager.h[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2][code][/size][/font] class HandlerSubscriptionBase; class Event;
typedef std::function<void (Event &event)> EventHandleFunc;
class EventManager { public: void NewEvent(Event &event); void RegisterSubscription(unsigned eventId, std::shared_ptr<HandlerSubscriptionBase> handlerSubscription); void UnregisterSubscription(unsigned eventId, std::shared_ptr<HandlerSubscriptionBase> handlerSubscription); private: typedef std::list<std::shared_ptr<HandlerSubscriptionBase>> SubscriptionList; typedef std::map<unsigned, SubscriptionList> SubscriptionListMap; SubscriptionListMap m_subscription; };[font=arial, verdana, tahoma, sans-serif][size=2][/code][/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]
[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]EventManager.cpp[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2][code][/size][/font]void TE::Events::EventManager::NewEvent( Event &event ){ SubscriptionListMap::iterator mapItr = m_subscription.find(event.EventId()); if (mapItr != m_subscription.end()) { SubscriptionList::iterator listItr = mapItr->second.begin(); for (; listItr != mapItr->second.end(); ++listItr) { (*listItr)->CallBack(event); } }}
void TE::Events::EventManager::RegisterSubscription(unsigned eventId, std::shared_ptr<HandlerSubscriptionBase> handlerSubscription){ bool regNewSubs = false; SubscriptionListMap::iterator mapItr = m_subscription.find(eventId); if (mapItr == m_subscription.end()) { regNewSubs = true; } else { SubscriptionList::iterator listItr = std::find(mapItr->second.begin(), mapItr->second.end(), handlerSubscription); if (listItr == mapItr->second.end()) regNewSubs = true; }
if (regNewSubs) { m_subscription[eventId].push_back(handlerSubscription); }}
void TE::Events::EventManager::UnregisterSubscription(unsigned eventId, std::shared_ptr<HandlerSubscriptionBase> handlerSubscription){ SubscriptionListMap::iterator mapItr = m_subscription.find(eventId); if (mapItr != m_subscription.end()) { SubscriptionList::iterator listItr = std::find(mapItr->second.begin(),mapItr->second.end(), handlerSubscription);
if (listItr != mapItr->second.end()) { if (mapItr->second.size() == 1) m_subscription.erase(mapItr); else mapItr->second.erase(listItr); } }}[font=arial, verdana, tahoma, sans-serif][size=2]
[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2][/code][/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]
[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]EventHandler.h[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2][code][/size][/font] class EventHandler { public: EventHandler(EventManager& eventManager);
virtual ~EventHandler(); protected: template<typename EventHandlerT, typename EventT> void RegisterSubscription(unsigned eventId, void (EventHandlerT::*eventCallback)(EventT&)); private: EventManager& m_eventManager; };
template<typename EventHandlerT, typename EventT> void EventHandler::RegisterSubscription( unsigned eventId, void (EventHandlerT::*eventCallback)(EventT&) ) { EventHandlerT* derivedThisPtr = static_cast<EventHandlerT*>(this); std::shared_ptr<HandlerSubscriptionBase> newSubscription(new HandlerSubscription<EventHandlerT, EventT>(*derivedThisPtr, eventCallback)); m_eventManager.RegisterSubscription(eventId, newSubscription); };[font=arial, verdana, tahoma, sans-serif][size=2][/code][/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]
[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]Usage:[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]
[/size][/font][font=arial, verdana, tahoma, sans-serif][size=2][code][/size][/font][font=arial, verdana, tahoma, sans-serif][size=2]
[/size][/font] class KeyboardEvent : public Events::Event { public: KeyboardEvent(int inputState, TEInput teInput ) : Events::Event(tekKeyboardEvent), m_inputState(inputState), m_teInput(teInput) {}
int InputState() { return m_inputState; }
TEInput TeInput() { return m_teInput; } private: int m_inputState; TEInput m_teInput; };[font=arial, verdana, tahoma, sans-serif][size=2]
[/size][/font]class InputTest : public TE::Events::EventHandler{public: InputTest(TE::Events::EventManager& eventManager) : EventHandler(eventManager) { RegisterSubscription(TE::Window::tekKeyboardEvent, &InputTest::HandleEvent); }
~InputTest() {
}
void HandleEvent(TE::Window::KeyboardEvent& keybEvent) { int state = keybEvent.InputState(); if (state == TE::Window::tekInputStateDown) { bool test = true; } else if (state == TE::Window::tekInputStateContinued) { bool test = true; } else if (state == TE::Window::tekInputStateUp) { bool test = true; } }};
TE::Window::KeyboardEvent testEv(TE::Window::tekInputStateDown, TE::Window::tekInputKeyX); eventManager.NewEvent(testEv);[font=arial, verdana, tahoma, sans-serif][size=2][/code][/size][/font]

Share this post


Link to post
Yes I've used the visitor pattern before.. guess I could do that.. this is how I solved it with the non template base class I mentioned in the previous post.. it works, but it feels hacky :P
Event.h
[code]
class Event
{
public:
explicit Event(unsigned id) : m_eventId(id){}

virtual ~Event(){}

unsigned EventId() const
{
return m_eventId;
}
private:
unsigned m_eventId;
};
[/code]

EventSubscription.h
[code]
class HandlerSubscriptionBase
{
public:
virtual ~HandlerSubscriptionBase(){}
virtual void CallBack(Event & event) = 0;
bool operator==(const HandlerSubscriptionBase& rhs) const
{
return &rhs == this;
}
};

template <typename EventHandlerT, typename EventT>
class HandlerSubscription : public HandlerSubscriptionBase
{
public:
typedef void (EventHandlerT::*EventCallback)(EventT&);

HandlerSubscription(EventHandlerT& eventHandler, EventCallback callback)
: m_eventHandler(eventHandler), m_callback(callback){}

void CallBack(Event& event)
{
(m_eventHandler.*m_callback)(static_cast<EventT&>(event));
}
private:
EventHandlerT& m_eventHandler;
EventCallback m_callback;
};
[/code]

EventManager.h
[code]
class HandlerSubscriptionBase;
class Event;

typedef std::function<void (Event &event)> EventHandleFunc;

class EventManager
{
public:
void NewEvent(Event &event);
void RegisterSubscription(unsigned eventId, std::shared_ptr<HandlerSubscriptionBase> handlerSubscription);
void UnregisterSubscription(unsigned eventId, std::shared_ptr<HandlerSubscriptionBase> handlerSubscription);
private:
typedef std::list<std::shared_ptr<HandlerSubscriptionBase>> SubscriptionList;
typedef std::map<unsigned, SubscriptionList> SubscriptionListMap;

SubscriptionListMap m_subscription;
};
[/code]

EventManager.cpp
[code]
void TE::Events::EventManager::NewEvent( Event &event )
{
SubscriptionListMap::iterator mapItr = m_subscription.find(event.EventId());
if (mapItr != m_subscription.end())
{
SubscriptionList::iterator listItr = mapItr->second.begin();
for (; listItr != mapItr->second.end(); ++listItr)
{
(*listItr)->CallBack(event);
}
}
}

void TE::Events::EventManager::RegisterSubscription(unsigned eventId, std::shared_ptr<HandlerSubscriptionBase> handlerSubscription)
{
bool regNewSubs = false;
SubscriptionListMap::iterator mapItr = m_subscription.find(eventId);

if (mapItr == m_subscription.end())
{
regNewSubs = true;
}
else
{
SubscriptionList::iterator listItr = std::find(mapItr->second.begin(), mapItr->second.end(), handlerSubscription);
if (listItr == mapItr->second.end())
regNewSubs = true;
}

if (regNewSubs)
{
m_subscription[eventId].push_back(handlerSubscription);
}
}

void TE::Events::EventManager::UnregisterSubscription(unsigned eventId, std::shared_ptr<HandlerSubscriptionBase> handlerSubscription)
{
SubscriptionListMap::iterator mapItr = m_subscription.find(eventId);

if (mapItr != m_subscription.end())
{
SubscriptionList::iterator listItr = std::find(mapItr->second.begin(),mapItr->second.end(), handlerSubscription);

if (listItr != mapItr->second.end())
{
if (mapItr->second.size() == 1)
m_subscription.erase(mapItr);
else
mapItr->second.erase(listItr);
}
}
}

[/code]

EventHandler.h
[code]
class EventHandler
{
public:
EventHandler(EventManager& eventManager);

virtual ~EventHandler();
protected:
template<typename EventHandlerT, typename EventT>
void RegisterSubscription(unsigned eventId, void (EventHandlerT::*eventCallback)(EventT&));
private:
EventManager& m_eventManager;
};

template<typename EventHandlerT, typename EventT>
void EventHandler::RegisterSubscription( unsigned eventId, void (EventHandlerT::*eventCallback)(EventT&) )
{
EventHandlerT* derivedThisPtr = static_cast<EventHandlerT*>(this);
std::shared_ptr<HandlerSubscriptionBase> newSubscription(new HandlerSubscription<EventHandlerT, EventT>(*derivedThisPtr, eventCallback));
m_eventManager.RegisterSubscription(eventId, newSubscription);
};
[/code]

Usage:

[code]



enum
{
tekKeyboardEvent = 'keyb'
};
class KeyboardEvent : public Events::Event
{
public:
KeyboardEvent(int inputState, TEInput teInput ) : Events::Event(tekKeyboardEvent), m_inputState(inputState), m_teInput(teInput)
{}

int InputState()
{
return m_inputState;
}

TEInput TeInput()
{
return m_teInput;
}
private:
int m_inputState;
TEInput m_teInput;
};

class InputTest : public TE::Events::EventHandler
{
public:
InputTest(TE::Events::EventManager& eventManager) : EventHandler(eventManager)
{
RegisterSubscription(TE::Window::tekKeyboardEvent, &InputTest::HandleEvent);
}

~InputTest()
{

}

void HandleEvent(TE::Window::KeyboardEvent& keybEvent)
{
int state = keybEvent.InputState();
if (state == TE::Window::tekInputStateDown)
{
bool test = true;
}
else if (state == TE::Window::tekInputStateContinued)
{
bool test = true;
}
else if (state == TE::Window::tekInputStateUp)
{
bool test = true;
}
}
};

TE::Window::KeyboardEvent testEv(TE::Window::tekInputStateDown, TE::Window::tekInputKeyX);
eventManager.NewEvent(testEv);
[/code]

Share this post


Link to post
Share on other sites
Is the non-template base class thing bad here and why?

Casting should be avoided, but is the static_cast here really that bad?

I don't want to implement a visitor for every event I add to the system.. if you dont convince me that is.. :P

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this