Ошибка в шаблонах в возможно неправильно разработанном менеджере ресурсов

Я создаю свою первую игру. Это будет Пакман или Снейк. Я собираюсь использовать DirectX 11.

Я сейчас пишу менеджер ресурсов. Я хочу сделать его максимально простым в использовании, но думаю, что он не очень хорошо продуман. Вот что я написал:

#pragma once

class Shader;
class Mesh;
class Texture;

typedef std::map<std::string, std::auto_ptr<Shader>>    shaders_map;
typedef std::map<std::string, std::auto_ptr<Mesh>>      meshes_map;
typedef std::map<std::string, std::auto_ptr<Texture>>   textures_map;

template<class C, class E>
inline int findElementInMap(const C& cont, E *ptr)
{
C::const_iterator it = cont.begin();
int i = 0;

while(it != cont.end())
{
if(it->second.get() == ptr) // ERROR AT THIS LINE!!!!
return i;

i++;
it++;
}

return -1;
}

class ResourceManager
{
public:
ResourceManager(void);
~ResourceManager(void);

template<class T>
inline T* get(const std::string &name)
{
if(typeid(T) == typeid(Shader)) {
return (T*)getShader(name);
}
else if(typeid(T) == typeid(Mesh)) {
return (T*)getMesh(name);
}
else if(typeid(T) == typeid(Texture)) {
return (T*)getTexture(name);
}

return nullptr;
}

Shader*     getShader(const std::string &name);
Mesh*       getMesh(const std::string &name);
Texture*    getTexture(const std::string &name);

template<class T>
inline bool add(T *ptr)
{
if(typeid(T) == typeid(Shader)) {
return addShader((Shader*)((void*)ptr));
}
else if(typeid(T) == typeid(Mesh)) {
return addMesh((Mesh*)((void*)ptr));
}
else if(typeid(T) == typeid(Texture)) {
return addTexture((Texture*)((void*)ptr));
}

return false;
}

bool        addShader(Shader *ptr);
bool        addMesh(Mesh *ptr);
bool        addTexture(Texture *ptr);

template<class E>
inline void release(E *ptr)
{
if(typeid(E) == typeid(Shader)) {
release<shaders_map, E>(shaders, (E*)((void*)ptr));
return;
}
else if(typeid(E) == typeid(Mesh)) {
release<meshes_map, E>(meshes, (E*)((void*)ptr));
return;
}
else if(typeid(E) == typeid(Texture)) {
release<textures_map, E>(textures, ptr);
}
}

// THIS METHOD CAUSES PROBLEM
template<class C, class E>
void release(C &container, E *ptr)
{
assert(ptr != nullptr);

int index = findElementInMap<C, E>(container, ptr);
if(index < 0)
return;

C::iterator it = container.begin();
it->second.release();
}
private:
shaders_map     shaders;
meshes_map      meshes;
textures_map    textures;
};

А теперь ошибка компиляции:

error C2440: '==' : cannot convert from 'Shader *' to 'Mesh *'
int findElementInMap<C,E>(const C &,E *)' being compiled
with
[
C=textures_map,
E=Shader
]

Таким образом, тип контейнера и тип элемента не совпадают. Любые идеи о том, как настроить его работу?

Или я должен построить новый менеджер ресурсов с нуля?

Редактировать:
Вот как я использую этот класс:

    Shader *sh = new Shader();
resourceManager.add<Shader>(sh);
resourceManager.release<Shader>(sh);

0

Решение

Много способов сделать это.

Вы могли бы сделать с простой перегрузкой:

bool        add(Shader *ptr){
return addShader(ptr);
}
bool        add(Mesh *ptr){
return addMesh(ptr);
}

bool        add(Texture *ptr){
return addTexture(ptr);
}

или если вы хотите использовать шаблоны, просто сделайте методы добавления и получения методов и специализируйте

template<class T>
void add(T *ptr){

}

и для каждого типа ресурса

template<>
ResourceManager<Texture>::add(Texture *ptr){
return addTexture(ptr);
}

template<>
ResourceManager<Shader>::add(Shader *ptr){
return addShader(ptr);
}

template<>
ResourceManager<Mesh>::add(Mesh *ptr){
return addMesh(ptr);
}

Другой более понятный вариант — создать шаблонный метод, который бы возвращал целевой контейнер.

template<typename T>
std::map<std::string, std::auto_ptr<typename T> > &getContainer(){}

Специализируйте его для возврата хорошего контейнера с указанным типом

template<>
std::map<std::string, std::auto_ptr<Mesh> > &ResourceManager::getContainer<Mesh>(){

return meshes_map;
}
template<>
std::map<std::string, std::auto_ptr<Texture> > &ResourceManager::getContainer<Texture>(){

return textures_map;
}
template<>
std::map<std::string, std::auto_ptr<Shader> > &ResourceManager::getContainer<Shader>(){

return shader_map;
}

Это бы выкинуло метод get, например, к чему-то вроде:

 template<typename T>
T* get(const std::string &name){
return getContainer<T>().get(name);
}

Отказ от ответственности: это просто халтура, я не скомпилировал его. Спросите, если у вас есть еще вопросы

Отредактируйте относительно вашей ошибки компиляции:
Ты звонишь resourceManager.release<Shader>(sh);
Для рисунка замените E на Shader в методе release, и вы увидите, что он не может скомпилироваться. релиз (текстуры, ptr)
Для того, чтобы ваш метод релиза компилировался, вы должны приводить его явно:

template<class E>
inline void release(E *ptr)
{
if(typeid(E) == typeid(Shader)) {
release<shaders_map, Shader>(shaders, (Shader*)((void*)ptr));
return;
}
else if(typeid(E) == typeid(Mesh)) {
release<meshes_map, Mesh>(meshes, (Mesh*)((void*)ptr));
return;
}
else if(typeid(E) == typeid(Texture)) {
release<textures_map, Texture>(textures, (Texture*)((void*)ptr));
}
}
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]