2016-11-25 62 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>(); 
}