Класс, который создает новые контейнеры для типа, известного из вызова его функции-члена шаблона

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

    cResMgr<cTexture> textures;
cResMgr<cSound> sounds;

Что я хочу сделать, это:

    cResMgr resources;
resources.add<cTexture>(...);
resources.get<cSound>(...);

По сути, мой менеджер ресурсов имеет функции «получить» и «добавить». Я хочу, чтобы при первом вызове функции для любого типа он создавал для нее контейнер. Когда он вызывается в следующий раз, он просто есть (он похож на статическую переменную в функции)

Вопрос в том, как я могу это реализовать? Единственное решение, которое я могу придумать, — это чтобы каждый ресурс был производным от пустого базового класса cResource, чтобы у меня был один контейнер указателей на cResource. Проблема в том, что типы ресурсов не мои (они из внешней библиотеки)

Какие-либо решения?

2

Решение

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

Кроме того, если коллекции могут быть статичными на глобальном уровне, зачем вам пример менеджера ресурсов?

В любом случае, это должно делать то, что вы описываете:

#include <string>
#include <map>

typedef double cTexture;
typedef std::string cSound;

struct cResMgr
{
template <typename T>
void add(std::string const& id, T const& v) const
{
mapFor<T>()[id] = v;
}

template <typename T>
T& get(std::string const& id) const
{
return mapFor<T>().at(id);
}

private:
template <typename T>
static std::map<std::string, T> mapFor()
{
static std::map<std::string, T> _theMap;
return _theMap;
}
};

int main()
{
cResMgr resources;
resources.add<cTexture>("wall", cTexture {});
resources.get<cSound>("sad_trombone");
}
2

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

Вы были на правильном пути с базовым классом для стирания типов, и ваш менеджер ресурсов держал указатели на его ресурсы. Как вы и предполагали, необоснованное бремя заставлять пользователей вашей системы ресурсов извлекать свои ресурсы из базового класса.

Итак, что вам нужно сделать, это создать пару классов, чтобы обернуть ресурс …

class ResourceBase
{
/*...*/
};

template<typename T>
class Resource : public ResourceBase
{
/* contains a T. T is the user's resource */
};

Затем ваш менеджер ресурсов может содержать список указателей ResourceBase. Когда пользователь говорит resources.get<cSound>("sound7"); Вы можете посмотреть вверх ResourceBase указатель (если есть) уменьшить его до Resource<cSound> и вернуть cSound содержатся.

1

Вы можете использовать карту. Конечно, это решается во время выполнения, что в некоторой степени противоречит цели шаблонов — максимально разрешать во время компиляции. Кроме того, контейнер будет немного сложнее, потому что контейнеры не имеют некоторого абстрактного базового класса. Я бы использовал Boost.Any для этого. Тогда это выглядит так:

template<res_type>
container<res_type>& get()
{
map<type_info, boost::any>::iterator it = map.find(typeid(res_type));
if(it == map.end())
map[typeid(res_type)] = container<res_type>();
boost::any& c = map[typeid(res_type)];
return boost::any_cast<container<res_type> >(c);
}

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

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector