将 RTTI 散列与模板函数一起使用

Using RTTI hash with a template function

我知道模板是编译时的,与类型信息相关的是运行时的,但我想知道我是否可以完成我的特定任务。

我有一个使用模板创建特定类型对象的工厂方法;我还有一个预加载器(从磁盘读取数据),它确定要创建什么类型的对象,但实际上并不创建它——这是创建者的责任,按需执行。

void Creator::Spawn(Preloader* pl)
{
    std::unordered_map<size_t, std::type_index>   hashmap;

    // assume ObjectType is simply a wrapper around a hash
    hashmap[ObjectType<Type1>::GetType().Hash()] = typeid(Type1);
    hashmap[ObjectType<Type2>::GetType().Hash()] = typeid(Type2);

    for ( auto& const i : pl->GetPreloadInfo() )
    {
        size_t  hash = i->type_hash.Hash();

        // similar-to-desired usage
        FactoryCreate<hashmap[hash]>();
    }
}

有什么办法可以实现吗?显然我可以对每个进行手动检查,如下所示,但充其量是令人讨厌的。

        // poor, manual implementation
        if ( hash == ObjectType<Type1>::GetType().Hash() )
            FactoryCreate<Type1>();
        else if ( hash == ObjectType<Type2>::GetType().Hash() )
            FactoryCreate<Type2>();

到目前为止,我尝试过的所有内容都存在运行时与编译时差异,尽管我绝对不知道所有可能有帮助的最新 C++11 技巧(C++14 不可用)。

这里有部分相关问题:Use data type (class type) as key in a map

假设哈希部分是一成不变的,您可以直接创建从这些类型哈希到您的工厂函数的映射:

using map_type = std::unordered_map<size_t, std::function<void()>>;

template <class... Ts>
map_type create_hash_map() {
    map_type map;

    // emplace (hash<T>, FactoryCreate<T>) for each T
    using swallow = int[];
    (void)swallow{0,
        (void(
            map.emplace(ObjectType<Ts>::GetType().Hash(),
                []{ FactoryCreate<Ts>(); }
                )
        ), 0)...
    };

    return map;
}

那么我们就可以直接使用那个地图了:

void Creator::Spawn(Preloader* pl)
{
    static auto hashmap = create_hash_map<Type1, Type2>();

    for ( auto& const i : pl->GetPreloadInfo() )
    {
        size_t  hash = i->type_hash.Hash();
        hashmap[hash]();
    }
}

它没有错误检查,所以如果 hash 实际上不在地图中,您将从 std::function 中得到一个 bad_function_call 异常。如果您需要错误检查,您可以先在地图中查找:

auto it = hashmap.find(hash);
if (it != hashmap.end()) {
    (it->second)(); 
}
else {
    // error!
}