简体   繁体   English

如何在STL容器中存储具有抽象模板类型的抽象模板类?

[英]How to store an abstract templated class with an abstract template type in STL container?

I hope the title is not misleading, but I could not find the right language to define my problem in one question. 我希望标题不会引起误解,但我找不到在一个问题中定义问题的正确语言。

Recently I've been trying to implement "CQRS Command Handler" design pattern using C++. 最近,我一直在尝试使用C ++实现“ CQRS命令处理程序”设计模式。 I have 2 hierarchies that I have to marry together: 我必须将两个层次结构结合在一起:

  • ICommand 指令

     struct ICommand { virtual ~ICommand() = default; }; struct SampleCommand : ICommand { int sampleParameter; SampleCommand() : sampleParameter(0) { } explicit SampleCommand(const int sampleParameter) { this->sampleParameter = sampleParameter; } }; 
  • ICommandHandler ICommandHandler

     template<typename T, typename = std::enable_if_t<std::is_base_of<ICommand, std::decay_t<T>>::value>> struct ICommandHandler { virtual void Handle(std::shared_ptr<T> command) = 0; virtual ~ICommandHandler() = default; }; class SampleCommandHandler : public ICommandHandler<SampleCommand> { public: void Handle(std::shared_ptr<SampleCommand> command) override { std::cout << "sampleParameter " << command->sampleParameter << std::endl; } }; 

Last piece I need to implement is a dispatcher which takes a command, finds a handler and delegates a command to a found handler. 我需要实现的最后一部分是一个调度程序,该调度程序接受命令,找到处理程序并将命令委托给找到的处理程序。 First idea that come to my mind was to expose some handler registering API in dispatcher and write dispatch method that would simply try to dynamic_cast all the registered handlers and if some cast was successful it would invoke found handler as shown below: 我想到的第一个想法是在分派器中公开一些处理程序注册API,并编写分派方法,该方法将尝试对所有已注册的处理程序进行动态广播,如果某些转换成功,它将调用找到的处理程序,如下所示:

class Dispatcher
{
public:

template<typename T>
void Dispatch(std::shared_ptr<T> command)
{
    auto handler = std::find_if(std::begin(_handlers), std::end(_handlers), [](auto handler)
    {
        return dynamic_cast<ICommandHandler<T>*>(handler);
    });

    if(handler != std::end(_handlers))
    {
        (*handler)->Handle(command);
    }
}

private:
    std::vector<?> _handlers;
};

The question is: what type should "_handlers" std::vector store to make the Dispatcher::Dispatch method work fine and if this is even possible? 问题是:“ _ handlers” std :: vector应该存储什么类型才能使Dispatcher :: Dispatch方法正常工作,甚至可以实现吗?

What I have tried so far: 到目前为止我尝试过的是:

  • std::vector< ICommandHandler *> - Did not compile, because casting a concrete handler to ICommandHandler< ICommand> *> is not possible. std :: vector <ICommandHandler *>-无法编译,因为无法将具体处理程序强制转换为ICommandHandler <ICommand> *>。

     Error C2440 'initializing': cannot convert from 'SampleCommandHandler *' to 'ICommandHandler<ICommand,void> *' 
  • std::vector< void* > - Did not compile as dynamic_cast cannot be applied to void* std :: vector <void *>-未编译,因为dynamic_cast无法应用于void *

You have a bunch of pointless (at least to me) polymorphism here; 这里有很多毫无意义的(至少对我来说)多态性; I'd split the container of handlers based on what they handle, instead of using one vector. 我将根据处理程序的容器拆分处理程序容器,而不是使用一个向量。 Like a map/unordered map from typeindex to handler; 就像从typeindex到处理程序的映射/无序映射; or, have a fixed set of types to handle. 或者,要处理一组固定的类型。

But to solve the problem asked: 但是要解决问题问:

struct ICommandHandlerBase{
  virtual ~ICommandHandlerBase(){};
};
template<typename T, typename = std::enable_if_t<std::is_base_of<ICommand, std::decay_t<T>>::value>>
struct ICommandHandler:ICommandHandlerBase
{

now store a vector of ICommandHandlerBase* or unique_ptr<ICommandHandlerBase> . 现在存储一个ICommandHandlerBase*unique_ptr<ICommandHandlerBase>的向量。

Certainly use a map or unordered map to do the look-up. 当然可以使用地图或无序地图进行查找。 If you must, you could use a (unordered) set with a custom comparator. 如果必须的话,可以将(无序)集合与自定义比较器一起使用。 Though that doesn't answer your question :-) 虽然那不能回答你的问题:-)

Assuming your handlers really are polymorphic, then your map or set will have to be pointers to the interface ICommandHandler. 假设您的处理程序确实是多态的,那么您的映射或集合将必须是指向接口ICommandHandler的指针。 They should not be raw pointers, but could be some flavour of smart pointer. 它们不应该是原始指针,而可以是某种智能指针。

Using std::shared_ptr means that your handler object lifetime is guaranteed while processing an event - if it also takes a shared_ptr, even if the event is removed from the mapping (either inside the handler or by another thread or handler), but comes with added internal complexity. 使用std :: shared_ptr意味着处理事件时可以保证处理程序对象的生存期-即使它从映射中删除(无论是在处理程序内部还是由另一个线程或处理程序删除),但它也需要一个shared_ptr,但附带增加了内部复杂性。

The implementation of std::unique_ptr is much simpler and can work well when you know a handler can't be interrupted. std :: unique_ptr的实现要简单得多,并且当您知道不能中断处理程序时可以很好地工作。 Note that the client code only sees the raw pointer - it must not steal the unique_ptr! 请注意,客户端代码只能看到原始指针-不能窃取unique_ptr!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM