检索访问者模式中 class 模板的类型
Retreive the type of a class template in a visitor pattern
我正在尝试使用模板、访问者模式并在 CRTP 的帮助下编写一个消息传递系统。我理解这些概念,但仍然处于必须检索 "lost" 类型的情况。我有一个 Base
class,我想找一个 Derived<T>
。那是 "two" 类型来推断 [Derived
可以是任何东西,T
可以是任何东西](即使它被认为是一种类型)。
我尝试使用第二个访问者模式,这看起来很笨重而且很疯狂,但我没有找到任何可行的解决方案。即使它是游戏相关的,它只是作为一个例子,它可以应用于我想的其他程序,我不能在另一个上下文中公开它。
这是我使用的命名方式(带有不必要的示例):
SubscriberBase
是一个 class 发送和接收消息(像网络客户端)
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
。它可以是任何 "concrete" 订阅者;在这种情况下,例如 EntityCache
或其他类似 Logger
、CommandRecorder
...
我尝试将另一个 CRTP 与另一个 class:
结合使用
class SubscriberBase {};
template<typename TSubscriber>
class Subscriber : public SubscriberBase { /* some other visitor pattern ? */ };
class EntityCache : public Subscriber<EntityCache>, /* ... */
没有成功。
感谢所有想法,谢谢:)
我放弃了这个想法并认为 "Well, KISS my .." 所以我决定采用更简单的设计,使用正常和干净的代码的正常和干净的方法。
//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
}
我接受这个答案,因为它解决了问题,但由于我仍然对如何做感兴趣,如果有人在过去(可能没有)遇到过这个问题并处理过,请随时回答我会接受的。
我正在尝试使用模板、访问者模式并在 CRTP 的帮助下编写一个消息传递系统。我理解这些概念,但仍然处于必须检索 "lost" 类型的情况。我有一个 Base
class,我想找一个 Derived<T>
。那是 "two" 类型来推断 [Derived
可以是任何东西,T
可以是任何东西](即使它被认为是一种类型)。
我尝试使用第二个访问者模式,这看起来很笨重而且很疯狂,但我没有找到任何可行的解决方案。即使它是游戏相关的,它只是作为一个例子,它可以应用于我想的其他程序,我不能在另一个上下文中公开它。
这是我使用的命名方式(带有不必要的示例):
SubscriberBase
是一个 class 发送和接收消息(像网络客户端)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
。它可以是任何 "concrete" 订阅者;在这种情况下,例如 EntityCache
或其他类似 Logger
、CommandRecorder
...
我尝试将另一个 CRTP 与另一个 class:
结合使用class SubscriberBase {};
template<typename TSubscriber>
class Subscriber : public SubscriberBase { /* some other visitor pattern ? */ };
class EntityCache : public Subscriber<EntityCache>, /* ... */
没有成功。
感谢所有想法,谢谢:)
我放弃了这个想法并认为 "Well, KISS my .." 所以我决定采用更简单的设计,使用正常和干净的代码的正常和干净的方法。
//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
}
我接受这个答案,因为它解决了问题,但由于我仍然对如何做感兴趣,如果有人在过去(可能没有)遇到过这个问题并处理过,请随时回答我会接受的。