Event Dispatch System in C++

In C++, to implement event dispatching, function pointers need to be bound for event callback dispatching. In C++17, the class template std::function was introduced, which serves as a general-purpose polymorphic function wrapper. With it, flexibility is greatly enhanced, allowing for an easily extensible event callback mechanism through simple encapsulation. The specific implementation is as follows:

Event.h:

#pragma once
#include <functional>
#include <unordered_map>
namespace xm {
template<class... ArgTypes>
class Event {
public:
    using Callback = std::function<void(ArgTypes...)>;
    uint64_t AddCallback(Callback callback);
    uint64_t operator+=(Callback callback);
    bool RemoveCallback(uint64_t id);
    bool operator-=(uint64_t id);
    void RemoveAllCallbacks();
    uint64_t GetCallbackCount();
    void Invoke(ArgTypes... args);
private:
    std::unordered_map<uint64_t, Callback> m_callbacks;
    uint64_t m_addIdCount = 0;
};

template<class... ArgTypes>
uint64_t Event<ArgTypes...>::AddCallback(Callback callback) {
    uint64_t id = m_addIdCount++;
    m_callbacks.emplace(id, callback);
    return id;
}

template<class... ArgTypes>
uint64_t Event<ArgTypes...>::operator+=(Callback callback) {
    return AddCallback(callback);
}

template<class... ArgTypes>
bool Event<ArgTypes...>::RemoveCallback(uint64_t id) {
    return m_callbacks.erase(id) != 0;
}

template<class... ArgTypes>
bool Event<ArgTypes...>::operator-=(uint64_t id) {
    return RemoveCallback(id);
}

template<class... ArgTypes>
void Event<ArgTypes...>::RemoveAllCallbacks() {
    m_callbacks.clear();
}

template<class... ArgTypes>
uint64_t Event<ArgTypes...>::GetCallbackCount() {
    return m_callbacks.size();
}

template<class... ArgTypes>
void Event<ArgTypes...>::Invoke(ArgTypes... args) {
    for (auto const &[key, value] : m_callbacks)
        value(args...);
}
}

main.cpp:

#include "Event.h"
#include <iostream>
#include <string>

void Print(const std::string &name, int age) {
    std::cout << "Print: " << "name: " << name << ", age: " << age << std::endl;
}

class Test {
public:
    xm::Event<const std::string &, int> m_peopleEvent;
    void Print(const std::string &name, int age) {
        std::cout << "Test::Print: " << "name: " << name << ", age: " << age << std::endl;
        m_peopleEvent.Invoke(name, age);
    }
};

int main() {
    Test test;
    std::cout << "Before registering Event print" << std::endl;
    test.Print("Xiao Ming", 14);
    uint64_t callbackId = test.m_peopleEvent.AddCallback(Print);
    std::cout << "After registering Event print" << std::endl;
    test.Print("Xiao Hong", 13);
    std::cout << "After deleting Event registration print" << std::endl;
    test.m_peopleEvent.RemoveCallback(callbackId);
    test.Print("Xiao Mei", 14);
    return 0;
}

Output Result:

Event Dispatch System in C++

Leave a Comment