用于在不使用RTTI的情况下缓存不同派生类型的设计模式

Hos*_*ork 5 c++ design-patterns rtti c++11

假设我有一系列类都可以实现相同的接口,可能用于调度:

class Foo : public IScheduler {
public:
    Foo (Descriptor d) : IScheduler (d) {}
    /* methods */
};

class Bar : public IScheduler {
public:
    Bar (Descriptor d) : IScheduler (d) {}
    /* methods */
};
Run Code Online (Sandbox Code Playgroud)

现在假设我有一个Scheduler类,你可以要求为给定的描述符启动一个IScheduler派生类.如果它已经存在,您将获得它的引用.如果一个不存在,那么它会创建一个新的.

一个假设的调用将是这样的:

Foo & foo = scheduler->findOrCreate<Foo>(descriptor);
Run Code Online (Sandbox Code Playgroud)

实现它需要一个映射,其键(描述符,RTTI)映射到基类指针.然后你必须dynamic_cast.我猜这些东西都是这样的:

template<class ItemType>
ItemType & Scheduler::findOrCreate(Descriptor d)
{
    auto it = _map.find(SchedulerKey (d, typeid(ItemType)));
    if (it == _map.end()) {
        ItemType * newItem = new ItemType (d);
        _map[SchedulerKey (d, typeid(ItemType))] = newItem;
        return *newItem;
    }
    ItemType * existingItem = dynamic_cast<ItemType>(it->second);
    assert(existingItem != nullptr);
    return *existingItem;
}
Run Code Online (Sandbox Code Playgroud)

想知道是否有人有办法实现类似的结果而不依赖于这样的RTTI.也许每种计划的项目类型都有自己的地图实例的方式?设计模式,还是......?

Mat*_* M. 5

函数或类静态成员的地址保证是唯一的(据我们所知<),因此您可以使用这样的地址作为键.

template <typename T>
struct Id { static void Addressed(); };

template <typename ItemType>
ItemType const& Scheduler::Get(Descriptor d) {
    using Identifier = std::pair<Descriptor, void(*)()>;

    Identifier const key = std::make_pair(d, &Id<ItemType>::Addressed);

    IScheduler*& s = _map[key];

    if (s == nullptr) { s = new ItemType{d}; }

    return static_cast<ItemType&>(*s);
}
Run Code Online (Sandbox Code Playgroud)

注意使用operator[]避免双重查找并简化功能体.