2013-02-08 48 views
2

該問題可能很難理解,但問題很簡單,我將在這裏用簡單的語言描述它。 現在,我的資源同治是:從模板成員函數的調用中創建類型的新容器

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

我想要做的是:

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

基本上,我的資源管理器「得到」和「添加」功能。我希望當我第一次爲任何類型調用函數時,它會爲它創建一個容器。當它被下一次調用時,它就在那裏(它類似於函數中的靜態變量)

問題是,我該如何實現它?我能想到的唯一解決方案是讓每個資源都來自空的基類cResource,這樣我就可以擁有一個指向cResource的指針容器。問題是,資源類型不是我的(它們來自外部庫)

任何解決方案?

+0

「(它類似於函數中的靜態變量)」什麼讓你不使用它? – Grizzly 2013-02-08 21:55:26

+0

@Grizzly新的容器必須在運行時生成 - 即cResMgr不知道它必須存儲多少個容器。 – user1873947 2013-02-08 21:56:56

+0

那麼它不是每個資源類型的一個容器? – Grizzly 2013-02-08 21:58:56

回答

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"); 
} 
+0

謝謝,就是這樣。 – user1873947 2013-02-08 22:04:42

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

+0

很好的解決方法,謝謝。 – user1873947 2013-02-08 22:05:23

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); 
} 

我沒有編譯這個,但我希望它得到了點。最後,有一個問題:你真的有這麼多不同的類型,所有這些都是值得的麻煩或者是好奇心。

+0

爲什麼不加boost :: variant?在這裏看起來更多點 – sehe 2013-02-08 22:28:47

+0

如果你知道哪些類型會發生,你可以做到這一點。但如果你這樣做,整個問題將是沒有意義的,因爲那樣你可以簡單地存儲一些適當類型的不同容器。 – 2013-02-09 09:02:48

+0

好吧,因爲這是所有靜態類型,你根據定義知道哪些類型發生(或不會編譯)。在最複雜的情​​況下,您希望在resourcemanager實例化時傳遞一個類型列表。 – sehe 2013-02-09 12:17:43