I made this simple event system:
template<typename Func, typename Args>
class Event
{
public:
static void dispatch(Args args) noexcept
{
for (auto listener : listeners)
listener.second(args);
}
static void attach(const std::string& id, Func func) noexcept
{
listeners.insert({ id, func });
}
static void dettach(const std::string& id) noexcept
{
listeners.erase(id);
}
private:
static std::unordered_map<std::string, Func> listeners;
};
template<typename Func, typename Args>
std::unordered_map<std::string, Func> Event<Func, Args>::listeners;
What I wanted to do is to let me create any sort of event without needing to do a lot more code.
so for example in this code, if I want to add a KeyEvent
, for example, I could do this:
struct KeyArguments {
int key;
int state;
};
class KeyEvent : public Event<std::function<void(const KeyArguments&)>, KeyArguments>
{
};
And to use such code:
KeyArguments args;
args.key = Key::A;
args.state = State::KeyUp;
KeyEvent::attach("new", func);
KeyEvent::attach("new2", [](KeyArguments args) { std::cout << "The key that was pressed is " << args.key;});
KeyEvent::dispatch(args);
KeyEvent::dettach("new2");
KeyEvent::dispatch(args);
I also wanted to make the design reachable from anywhere in the code, this is why I used static
keyword, and this is the part that doesn't really "feel" good.
Should I really be using static in this case? Is there any cons in using such design?
I feel like using template
for this case is a bit overkill. For each event create a "new" class (the struct doesn't bother me). Do you think there is a way around that? Is it as bad as I think it is?
EDIT: The design goal was to create an event system that anyone could attach to and get notified when the specific event has happened.
For example in a game we would like to distribute an event for KeyPress
, so the event system (in the engine) would let the game programmer attach the Player::input
function to it, and if he would like, Menu::input
as well. Both of them will get notified when a KeyPress
event has happened.
KeyEvent
class. \$\endgroup\$attach
than the one defined in yourEvent
class. 2) You didn't explain what you want, but usually an event manager uses the id to raise a specific event i.e. call all the function pointers registered for a specific event id. Here, yourdispatch
function doesn't use thestd::string
key in themap
. So when you dispatch events, the class will dispatch all the events with the same parameters (all the function pointers that this class stored), whatever the name of the event is. \$\endgroup\$KeyEvent
(in a game) will call every function that attached to it to let them know a key was pressed. \$\endgroup\$