2017-04-21 63 views
1

我正在嘗試使用模板,訪問者模式和CRTPs的幫助編寫郵件系統。我理解這些概念,但仍然處於這種情況下,我必須回顧一種「迷失」類型。我有一個Base班,我想找到一個Derived<T>。這是推斷「兩種」的類型,即使它被認爲是一種類型,任何東西都可以是T在訪問者模式中檢索類模板的類型

我試圖利用第二個訪客模式,這看起來很沉重而且很瘋狂,但我沒有找到任何工作解決方案。即使它與遊戲有關,它只是一個例子,它可以應用於其他程序,我想,我不能在另一個環境中公開它。

這裏是我使用的命名(不必要的示例):

  • SubscriberBase是發送和接收消息(像一個網絡客戶端)
  • Broadcaster是用戶之間的橋(如網絡中的類交換機/服務器),幷包含一個向量SubscriberBase

我想出了這個最小代碼:

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

的問題是類型THE_ACTUAL_SUBSCRIBER_TYPE。它可以是任何「具體」用戶;在這種情況下,將例如EntityCache或別的像LoggerCommandRecorder ...

我試圖用加上另一個類另一個CRTP:

class SubscriberBase {}; 

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

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

沒有成功。

所有的想法表示讚賞,謝謝:)

回答

0

我放棄了這個想法,並認爲「好了,吻我。」所以我決定去一個簡單的設計,對於正常的清潔方法正常和乾淨的代碼。

//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 
} 

我接受這個答案,因爲它解決了這個問題,但由於我對如何做到這一點仍然有興趣,如果有人在過去遇到過這個問題(可能不是),並處理了它,覺得免費回答,我會接受它。