Creating a type-safe event system using std::type_index
can provide a flexible and efficient way to handle events in your application. Here's how you can implement such a system:
First, let's define our basic event structure and event handler interface:
#include <functional>
class Event {
public:
virtual ~Event() = default;
};
class MouseClickEvent : public Event {
public:
MouseClickEvent(int x, int y)
: x_(x), y_(y) {}
int GetX() const { return x_; }
int GetY() const { return y_; }
private:
int x_, y_;
};
class KeyPressEvent : public Event {
public:
KeyPressEvent(char key)
: key_(key) {}
char GetKey() const { return key_; }
private:
char key_;
};
using EventHandler =
std::function<void(const Event&)>;
Now, let's create an EventManager
class that uses std::type_index
to manage different event types:
#include <functional>
#include <typeindex>
class Event {/*...*/};
class MouseClickEvent : public Event {/*...*/};
class KeyPressEvent : public Event {/*...*/};
using EventHandler =
std::function<void(const Event&)>;
class EventManager {
public:
template <typename T>
void Subscribe(EventHandler handler) {
static_assert(
std::is_base_of<Event, T>::value,
"T must inherit from Event"
);
handlers_[std::type_index(typeid(T))]
.push_back(handler);
}
template <typename T>
void Publish(const T& event) {
static_assert(
std::is_base_of<Event, T>::value,
"T must inherit from Event"
);
auto it = handlers_
.find(std::type_index(typeid(T)));
if (it != handlers_.end()) {
for (const auto& handler : it->second) {
handler(event);
}
}
}
private:
std::unordered_map<
std::type_index, std::vector<EventHandler>
> handlers_;
};
Let's create some example events and demonstrate how to use this system:
#include <functional>
#include <typeindex>
#include <iostream>
class Event {/*...*/};
class MouseClickEvent : public Event {/*...*/};
class KeyPressEvent : public Event {/*...*/};
using EventHandler =
std::function<void(const Event&)>;
class EventManager {/*...*/};
int main() {
EventManager eventManager;
// Subscribe to MouseClickEvent
eventManager.Subscribe<MouseClickEvent>(
[](const Event& e) {
const auto& mouseEvent =
static_cast<const MouseClickEvent&>(e);
std::cout << "Mouse clicked at ("
<< mouseEvent.GetX() << ", "
<< mouseEvent.GetY() << ")\n";
});
// Subscribe to KeyPressEvent
eventManager.Subscribe<KeyPressEvent>(
[](const Event& e) {
const auto& keyEvent =
static_cast<const KeyPressEvent&>(e);
std::cout << "Key pressed: "
<< keyEvent.GetKey() << "\n";
});
// Simulate some events
eventManager.Publish(MouseClickEvent(10, 20));
eventManager.Publish(KeyPressEvent('A'));
}
Mouse clicked at (10, 20)
Key pressed: A
EventManager
.std::type_index
provides fast lookup for event handlers.By using std::type_index
, we've created a flexible, type-safe event system that can be easily extended for various applications, from game development to GUI frameworks.
Answers to questions are automatically generated and may not have been reviewed.
typeid()
Learn to identify and react to object types at runtime using RTTI, dynamic casting and the typeid()
operator