2017-04-21 6 views
1

Ich versuche, ein Messaging-System mit Vorlagen, das Besuchermuster und mit Hilfe von CRTPs zu schreiben. Ich verstehe diese Konzepte, aber ich bin immer noch in einer Situation, in der ich einen "verlorenen" Typ wiederfinden muss. Ich habe eine Base Klasse und ich möchte eine Derived<T> finden. Das sind "zwei" Typen, die abzuleiten sind [Derived könnte alles Mögliche sein, T könnte alles sein] (selbst wenn es als ein Typ betrachtet wird).Retreive den Typ einer Klassenvorlage in einem Besuchermuster

Ich habe versucht, ein zweites Besuchermuster zu verwenden, das schwer und verrückt scheint, aber ich habe keine funktionierende Lösung gefunden. Auch wenn es spielbezogen ist, ist es nur ein Beispiel, es könnte auch auf andere Programme angewendet werden, ich kann es nicht in einem anderen Kontext darstellen. Hier

ist die Namensgebung I (mit unnötigen Beispielen) verwendet:

  • SubscriberBase ist eine Klasse, die Nachrichten sendet und empfängt (wie ein Netzwerk-Client)
  • Broadcaster die Brücke zwischen den Teilnehmern ist (wie ein Netzwerk Switch/Server) und enthält einen Vektor von SubscriberBase.

kam ich mit diesem minimalen Code oben:

class SubscriberBase {}; 

class Broadcaster { 
    std::vector<SubscriberBase*> subscribers; 
public: 
    template<typename TMessage> 
    void broadcast(TMessage& message) { 
     for(auto subscriber : subscribers) { 

      // <<< Here is my problem <<< 
      message.accept<THE_ACTUAL_SUBSCRIBER_TYPE>(subscriber); 

     } 
    } 

    void attach(SubscriberBase* subscriber) { 
     subscribers.push_back(subscriber); 
    } 
}; 

//Base class for handling messages of any type 

template<typename TMessage> 
class MessageHandler { 
public: 
    virtual void handleMessage(TMessage& message) {} 
}; 

//Base class for messages 

template<typename TMessage> 
class Message { 
    friend class Broadcaster; 
private: 

    //Visitor pattern with CRTP 
    template<typename TSubscriber> 
    void accept(TSubscriber* subscriber) { 
     subscriber->handleMessage(*static_cast<TMessage*>(this)); 
    } 

}; 

//Messages 

struct EntityCreated : public Message<EntityCreated> {}; 
struct EntityDestroyed : public Message<EntityDestroyed> {}; 
struct BurnAllGummyBears : public Message<BurnAllGummyBears> {}; 

//Subscribers 

class EntityCache : public SubscriberBase, 
    public MessageHandler<EntityCreated>, 
    public MessageHandler<EntityDestroyed>, 
    public MessageHandler<BurnAllGummyBears> 
{ 
public: 
    void handleMessage(EntityCreated& message) override { /* add to cache */ } 
    void handleMessage(EntityDestroyed& message) override { /* remove from cache */ } 
    //does not override BurnAllGummyBears because it's not relevant for EntityCache 
}; 

Das Problem THE_ACTUAL_SUBSCRIBER_TYPE der Typ ist. Es könnte jeder "konkrete" Abonnent sein; in diesem Fall wäre es sonst zum Beispiel EntityCache oder so etwas wie Logger, CommandRecorder ...

ich versucht, einen anderen CRTP mit einer anderen Klasse gekoppelt zu verwenden:

class SubscriberBase {}; 

template<typename TSubscriber> 
class Subscriber : public SubscriberBase { /* some other visitor pattern ? */ }; 

class EntityCache : public Subscriber<EntityCache>, /* ... */ 

ohne Erfolg.

Alle Ideen geschätzt, danke :)

Antwort

0

Ich habe diese Idee auf und dachte: „Nun, meinen Kuss ..“ so entschied ich mich für ein einfacheres Design zu gehen, der normale und sauberer Ansatz für ein normaler und sauberer Code.

//Messages 
struct EntityCreated {}; 
struct EntityDestroyed {}; 
struct ChopAllTrees {}; 
struct MakeGummyBearsEvil {}; 

//Subscriber is now a base class containing all of the message handlers 
class Subscriber { 
public: 
    virtual void handleMessage(EntityCreated& msg) {} 
    virtual void handleMessage(EntityDestroyed& msg) {} 
    virtual void handleMessage(ChopAllTrees& msg) {} 
    virtual void handleMessage(MakeGummyBearsEvil& msg) {} 
}; 

class Broadcaster { 
    std::vector<Subscriber*> subscribers; 
public:  
    template<typename M> 
    void broadcast(M& msg) { 
     for(auto subscriber : subscribers) { 
      subscriber->handleMessage(msg); 
     } 
    } 

    template<typename M> 
    void broadcast(M&& msg) { 
     M owner(msg); 
     broadcast(owner); 
    } 

    void attach(Subscriber* subscriber) { 
     auto it = std::find(subscribers.begin(), subscribers.end(), subscriber); 
     if(it == subscribers.end()) { 
      subscribers.push_back(subscriber); 
     } 
    } 

    void detach(Subscriber* subscriber) { 
     auto it = std::find(subscribers.begin(), subscribers.end(), subscriber); 
     if(it != subscribers.end()) { 
      subscribers.erase(it); 
     } 
    } 
}; 

//Subscribers simply inherits from Subscriber and overrides interesting handlers 
class EntityCache : public Subscriber { 
    void handleMessage(EntityCreated& msg) override { 
     std::cout << "Handling creation\n"; 
    } 
    void handleMessage(EntityDestroyed& msg) override { 
     std::cout << "Handling destruction\n"; 
    } 
}; 

class Eviler : public Subscriber { 
    void handleMessage(MakeGummyBearsEvil& msg) override { 
     std::cout << "Gummy bears are now evil!\n"; 
    } 
}; 

int main() { 
    EntityCache entityCache; 
    Eviler eviler; 

    Broadcaster broadcaster; 
    broadcaster.attach(&entityCache); 
    broadcaster.attach(&eviler); 

    EntityCreated entityCreated; 

    broadcaster.broadcast(entityCreated); //lvalue test 
    broadcaster.broadcast(MakeGummyBearsEvil()); //rvalue test 

    broadcaster.detach(&eviler); 

    broadcaster.broadcast(EntityDestroyed()); 
    broadcaster.broadcast(MakeGummyBearsEvil()); //no effect 
} 

Ich nehme diese Antwort, da es das Problem löst, aber da ich bin immer noch daran interessiert, wie man es tun, wenn jemand dieses Problem in der Vergangenheit aufgetretenen (wahrscheinlich nicht) und es gehandhabt, fühlt sich frei, zu antworten und ich werde es akzeptieren.