提问人:Aleix Rius 提问时间:10/1/2023 更新时间:10/1/2023 访问量:47
C++ [模板] 按类型查找合适的容器
C++ [templates] Finding proper container by type
问:
我正在做一个学习项目,我正在搞砸一些资源加载器,当我在按类型定义容器然后获取它们时遇到卡住时,我试图将其定义为尽可能通用的。
例如,如果我有一个,我该如何根据函数参数定义要选择哪一个?container<TypeA>
container<TypeB>
举个虚拟例子:
template <class T>
void DoFoo(T&& t)
{
// How to determine which container to use?
container<TypeA>.Add(t);
container<TypeB>.Add(t);
}
有关实际代码的更多扩展上下文:
class ResourceManager {
// Resources will be referenced by name --> "Main font", "Background music"...
using ResourceName = std::string_view;
// Functor to convert name to hash, in this case using std::hash (good enough).
using ResourceIDFactory = std::hash<ResourceName>;
// Hash type or resource ID will be the result of hashing the name: std::hash("Main Font").
using ResourceID = std::invoke_result<ResourceIDFactory, ResourceName>::type;
// Resource Handle is defined by it's own type trait.
template<typename T>
using ResourceMap = std::unordered_map < ResourceID, Resources::Resource<T>::HandleTy>;
public:
template <typename Resource, typename ... Args>
auto Load(ResourceName name, Args&& ... args) {
ResourceID id = GetResoruceID(name);
if (auto ptr = IsResourceLoaded<Resource>(id))
{
return *ptr;
}
auto handle = resourceLoader.Load<Resource>(std::forward<Args>(args)...);
// How do I find the correct containter to add the new handle?
}
private:
template<typename T>
Resources::Resource<T>::HandleTy* IsResourceLoaded(ResourceID id) {
// this is one of the worst functions I've ever wrote.
// Problem resides on finding the right container by resource type
// Might be solvable with some SFINAE and some dark magic. WIP.
if constexpr (std::is_same_v<T, Font>)
{
auto it = fontResources.find(id);
return (it != fontResources.end()) ? &(*it) : nullptr;
}
else if constexpr (std::is_same_v<T, Music>) {
auto it = musicResources.find(id);
return (it != musicResources.end()) ? &(*it) : nullptr;
}
else
{
// this might run unto compilation issue as it not type checked.
auto it = soundResources.find(id);
return (it != soundResources.end()) ? &(*it) : nullptr;
}
}
inline ResourceID GetResoruceID(ResourceName name)
{
return IdFactory(name);
}
private:
Resources::Loader resourceLoader;
ResourceIDFactory IdFactory;
// Ugly way, could not find a proper way to dynamically generate containers by type
ResourceMap<Font> fontResources;
ResourceMap<Music> musicResources;
ResourceMap<Sound> soundResources;
};
我正在使用 C++ 最新(因此如果需要,我可以使用一些 c++23 功能),但到目前为止,我不知道我应该往哪个方向走。
注意:我没有使用boost,因为我更喜欢从头开始学习。
提前致谢!
我做过的一些实验没有奏效或不喜欢结果:
使用此功能将强制逐个检查所有类型,这些类型不能很好地扩展并使所有功能膨胀。我想放弃这个选项。
if constexpr (std::is_same_v<A,B>)
尝试使用静态模板函数按类型生成哈希,并使其具有更高级别的容器:问题是值类型()不是同质的。
map<Typehash, Container<T>
Container<T>
答: 暂无答案
评论
map<Typehash, std::any>
std::any_cast<T>
IsResourceLoaded
Font
Music
Sound
Resource<T>
std::variant
std::visit
template<typename T> Resources::Resource<T>::HandleTy* IsResourceLoaded(ResourceID id);
template<> Resources::Resource<Font>::HandleTy* ResourceManager::IsResourceLoaded(ResourceID id) { /* implement using fontResources */ }