【问题标题】:Class that creates new containers for type known from its template member function's call为从其模板成员函数调用已知的类型创建新容器的类
【发布时间】:2013-02-08 21:50:46
【问题描述】:

这个问题可能很难理解,但问题很简单,我会在这里用简单的话来描述。 现在,我的资源管理是:

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

我想做的是:

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

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

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

有什么解决办法吗?

【问题讨论】:

  • "(类似于函数中的静态变量)" 是什么让你无法使用它?
  • @Grizzly 新容器必须在运行时生成 - 即 cResMgr 不知道它必须存储多少容器。
  • 所以不是每个资源类型一个容器?
  • 这需要线程安全吗?
  • @Grizly 现在我为每种资源类型提供一个容器,我希望有一个资源管理器来存储它们。

标签: c++ templates types containers factory


【解决方案1】:

我真的不知道你为什么不只为每种资源类型使用不同的资源管理器。

另外,如果集合可以是全局静态的,为什么需要资源管理器的实例

无论如何,这应该符合您的描述:

#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&lt;cSound&gt;("sound7"); 时,您可以查找ResourceBase 指针(如果有),将其向下转换为Resource&lt;cSound&gt; 并返回包含的cSound

    【讨论】:

      【解决方案3】:

      您可以使用地图。当然,这是在运行时解决的,这有点违背模板在编译时尽可能多地解决的目标。此外,容器会有点棘手,因为容器没有一些抽象基类。我会为此使用 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);
      }
      

      我没有编译这个,但我希望它能够理解这一点。最后,一个问题:你真的有这么多不同的类型,所有这些都值得麻烦还是好奇。

      【讨论】:

      • 如果你知道会出现哪些类型,你就可以做到。如果你这样做了,整个问题就没有实际意义了,因为你可以简单地存储几个不同类型的正确类型的容器。
      • 好吧,因为这都是静态类型的,根据定义,你知道出现了哪些类型(或者它不会编译)。在最“复杂”的情况下,您希望在资源管理器实例化时传递一个类型列表。
      猜你喜欢
      • 2010-12-22
      • 2017-10-26
      • 2019-12-06
      • 2011-07-06
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 2021-07-25
      相关资源
      最近更新 更多