从模板成员函数调用中为已知类型创建新容器的类

时间:2013-02-08 21:50:46

标签: c++ templates types containers factory

这个问题可能很难理解,但问题很简单,我将用简单的语言对其进行描述。 现在,我的资源管理是:

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

我想做的是:

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

基本上,我的资源管理器有“获取”和“添加”功能。我想要的是,当我第一次为cW函数调用函数时,它会为它创建一个容器。当它被调用下一次时,它就在那里(它与函数中的静态变量类似)

问题是,我该如何实施呢?我能想到的唯一解决方案是让每个资源都来自空基类cResource,这样我就可以拥有一个指向cResource的指针容器。问题是,资源类型不是我的(它们来自外部库)

任何解决方案?

3 个答案:

答案 0 :(得分: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");
}

答案 1 :(得分:1)

您使用基类进行了类型擦除,并让您的资源管理器保持指向其资源的指针。就像你暗示的那样,让资源系统的用户从基类派生资源是一种不合理的负担。

所以,你需要做的是创建一个包装资源的类......

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

答案 2 :(得分: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);
}

我没有编译这个,但我希望它能解决这个问题。最后,有一个问题:你真的有这么多不同的类型,这一切都值得麻烦或好奇。