2017-04-21 126 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 
} 

我接受这个答案,因为它解决了这个问题,但由于我对如何做到这一点仍然有兴趣,如果有人在过去遇到过这个问题(可能不是),并处理了它,觉得免费回答,我会接受它。