2016-11-25 64 views
1

我已經創建了一個使用模板的動態擴展容器類。 但是,這隻能存儲相同數據類型的對象。 如何創建一個動態擴展的容器類,並且可以在展開類時容納指定類型的對象。更改模板參數C++

這對於如: -

如果obj是一個對象說類 我應該能夠調用一個函數說

obj.foo<int>(25); 

之後,同樣的功能,存儲第二部件爲布爾類型或浮動

obj.foo<bool>(true); 

有沒有辦法做到這一點我有想過模板,但我不能設置一個類的成員在不知道數據類型b手前

+0

不是真的,如果你有這些調用遍佈由於容器不能事先用什麼模板參數知道的地方'foo'將被調用。你可以訴諸'void *'或者更好的'std(C++ 17)/ boost :: any'。但是這違背了'foo'上模板參數的模板原因。 –

+0

@GillBates所以我沒辦法做到這一點? – WARhead

+0

不,沒有辦法,不在保存的同一個容器對象內。除非使用上述方法。 –

回答

2

C++ 17 introduces std::any,一個可以存儲任意對象的類,所以你可以簡單地使用你的容器類來存儲std::any對象。

這實際上只是一個C++庫的補充,它並沒有真正使用任何核心C++語言特性,因此在C++ 17之前,可以簡單地實現它們自己的std::any版本。

但是,這是相當多的工作。例如,您將需要使用高級語言功能,例如放置新功能。這不是幾段可以解釋的事情。

但是,另一種可能的方式是在利用std::shared_ptr的類型擦除功能的情況下完成此操作,並讓您的容器存儲std::shared_ptr<void>對象。您的插入功能模板可以使用make_shared構造一個std::shared_ptr以將其添加到您的容器中,然後使用std::static_pointer_cast<void>將其轉換爲std::shared_ptr<void>,然後將其存儲在您的容器中。

但是,當然,你將不得不找出存儲在你的容器中的每個對象的類型,這可能會非常痛苦。

如果您的容器可以存儲的所有不同類都是相同基類的所有子類,那麼您只需將std::shared_ptr<BaseClass>推入容器中,然後每天調用它。這將是更直接的解決方案。

+0

我一直在尋找一個更簡單,易於理解的解決方案,但它似乎是我的頭... – WARhead

+1

沒關係。這是C++最神祕的部分之一。 –

0

這裏是一個C++ 03路:

#include <vector> 
#include <string> 
#include <typeinfo> 

class Entry{ 
public: 
    class Exception_TypeFail : std::exception { 
    public: 
     ~Exception_TypeFail() throw() { 
     } 

     const char* what() const throw(){ 
      return "Failed to cast"; 
     } 
    }; 

    class PolymorphInterface{ 
    public: 
     virtual ~PolymorphInterface() {}; 
     virtual bool isType(const std::type_info &testType) const =0; 
    }; 

    template<typename TYPE> 
    class Polymorph : public PolymorphInterface{ 
    private: 
     TYPE mData; 

    public: 
     Polymorph(const TYPE &copyMe) 
     : mData(copyMe) { 
     } 

     bool isType(const std::type_info &testType) const { 
      return testType == typeid(mData); 
     } 

     TYPE& get(){ 
      return mData; 
     } 
    }; 

    Entry(PolymorphInterface *manageMe) 
    : mManageMe(manageMe) { 
    } 

    Entry(const Entry &copyMe) 
    : mManageMe(const_cast<Entry&>(copyMe).mManageMe) { 
     const_cast<Entry&>(copyMe).mManageMe = NULL; 
    } 

    ~Entry(){ 
     delete mManageMe; 
    } 

    template<typename TYPE> 
    bool isType(){ 
     return mManageMe->isType(typeid(TYPE)); 
    } 

    template<typename TYPE> 
    TYPE& get(){ 
     if(!mManageMe->isType(typeid(TYPE))) 
      throw Exception_TypeFail(); 

     return dynamic_cast< Polymorph<TYPE>* >(mManageMe)->get(); 
    } 

    template<typename TYPE> 
    const TYPE& getConst() const { 
     if(!mManageMe->isType(typeid(TYPE))) 
      throw Exception_TypeFail(); 

     return dynamic_cast< Polymorph<TYPE>* >(mManageMe)->get(); 
    } 

private: 
    PolymorphInterface *mManageMe; 
}; 


int main(){ 
    //- I'm using std lib containers the same way your container may work 
    std::vector<Entry> magicContain; 
    magicContain.push_back(
     Entry(new Entry::Polymorph<int>(42)) 
    ); 
    magicContain.push_back(
     Entry(new Entry::Polymorph<float>(1.5f)) 
    ); 
    magicContain.push_back(
     Entry(new Entry::Polymorph<std::string>("hi there.")) 
    ); 

    if(magicContain[0].isType<long>()) 
     long iShouldNotBeHere = 0; 

    std::string impressYourFriends; 
    if(magicContain[2].isType<std::string>()) 
     impressYourFriends = magicContain[2].get<std::string>(); 

    const std::vector<Entry> frozenMagic(magicContain); 
    return frozenMagic[0].getConst<int>(); 
}