将 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!
}
我知道模板是编译时的,与类型信息相关的是运行时的,但我想知道我是否可以完成我的特定任务。
我有一个使用模板创建特定类型对象的工厂方法;我还有一个预加载器(从磁盘读取数据),它确定要创建什么类型的对象,但实际上并不创建它——这是创建者的责任,按需执行。
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!
}