Run Time Type Information (RTTI) and typeid()

Type-Safe Event System with std::type_index

How can I use std::type_index to implement a type-safe event system?

Illustration representing computer hardware

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:

Basic Event System Structure

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&)>;

Event Manager

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_; };

Usage Example

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

Benefits of This Approach

  1. Type Safety: The system ensures that only proper Event types are subscribed to and published.
  2. Flexibility: You can easily add new event types without modifying the EventManager.
  3. Efficiency: std::type_index provides fast lookup for event handlers.

Considerations

  1. Memory Management: Be cautious with lambda captures to avoid dangling references.
  2. Performance: While efficient, consider the impact of frequent dynamic casting in performance-critical code.
  3. Thread Safety: This implementation is not thread-safe. Add mutexes if needed in a multi-threaded environment.

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.

This Question is from the Lesson:

Run Time Type Information (RTTI) and typeid()

Learn to identify and react to object types at runtime using RTTI, dynamic casting and the typeid() operator

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

Run Time Type Information (RTTI) and typeid()

Learn to identify and react to object types at runtime using RTTI, dynamic casting and the typeid() operator

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 125 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved