Je voudrais construire un bus d'événements générique en c ++, qui permet de transmettre des messages de type arbitraire, et qui permet d'enregistrer des gestionnaires en fonction du type du message. IE je voudrais ...

0
htuy42 14 mars 2021 à 23:22

1 réponse

Meilleure réponse

En extrapolant à partir des réponses similaires que j'ai mises dans les commentaires, cela fonctionne pour moi:

#include <iostream>
#include <unordered_map>
#include <typeindex>

struct OutputType {};

struct EventType1 {};
struct EventType2 {};
struct EventType3 {};

OutputType event1(EventType1 event) { std::cout << "Called: " << __PRETTY_FUNCTION__ << "\n"; }
OutputType event2(EventType2 event) { std::cout << "Called: " << __PRETTY_FUNCTION__ << "\n"; }

// we store the function pointers as OutputType(*)()
// but the type_index lookup returns a function pointer
// belonging to EventType so it is safe to cast it back
// to the real pointer type

std::unordered_map<std::type_index,OutputType(*)()> handlers;

template<typename EventType>
void registerHandler(OutputType (*handler)(EventType))
{
    handlers.insert({std::type_index(typeid(EventType)),(OutputType(*)()) handler});
}

template<typename EventType>
OutputType callHandler(EventType event)
{
    // we can use find and then check if it was found
    // or we can use at and let it throw std::out_of_range if it is not found
    
    auto it = handlers.find(std::type_index(typeid(EventType)));
    if (it == handlers.end())
        return {}; // need to do something with this
        
    return ((OutputType(*)(EventType)) it->second)(event);
}

int main()
{
    registerHandler(event1);
    registerHandler(event2);
    
    EventType1 event1; // will be found
    callHandler(event1);

    EventType2 event2; // will be found
    callHandler(event2);

    EventType3 event3; // won't be found
    callHandler(event3);

    return 0;
}

Essayez-le sur https://onlinegdb.com/H1nCABh7O

La seule chose que je ne pourrais pas faire mieux est la suivante: un cast est nécessaire pour convertir le type du pointeur de fonction afin que la carte n'ait pas besoin de connaître le type.

J'ai essayé de résoudre ce problème en demandant à la carte de prendre un pointeur de classe de base polymorphe vers une classe dérivée basée sur un modèle, mais il n'y a aucun moyen de créer un opérateur virtuel () qui prend un paramètre EventType basé sur un modèle, donc un cast vers la classe dérivée est toujours nécessaire. ..

1
Jerry Jeremiah 15 mars 2021 à 03:09