![](/img/trans.png)
[英]Can non-templated nested classes of class templates be implemented in a C++ header?
[英]Can we “wrap” templated classes with non-templated classes in C++?
免責聲明:恐怕我的問題的簡短答案是“不可能”。 但是由於我不是C ++專家,所以我認為我仍然可以在這里嘗試一下,也許有某種我不知道的解決方案。
因此,我有模板化的類似於容器的類MyContainer
,它在內部將數據存儲在std::list<T>
,其中T
是類模板類型。 這很好。
現在,我想添加另一個類,該類必須在std::map<std::string, MyContainer>
該模板化容器類的實例。 但是,編譯器要求我為映射的值部分提供模板類類型,如std::map<std::string, MyContainer<T>>
。 但是我寧願在這里省略該模板,因為這反過來又需要我為包裝器類使用模板。
因此,我的問題是:是否有一種方法可以實現我想要做的事情,至少要在某種程度上省略包裝類的模板類型? 還是在C ++中這是不可能的,因為在任何情況下編譯器都需要該信息?
做到這一點的一種常用技術是繼承。
您使MyContainer<T>
繼承自某些基類,例如MyBaseContainer
。 MyBaseContainer
不是模板類,但MyContainer
是模板類。 MyBaseContainer
類具有模板類覆蓋的虛函數。
然后,使您的地圖類型為std::map<std::string, MyBaseContainer*>
。 它將能夠在其存儲的容器上調用虛擬函數,而不必知道每個容器的模板類型。
這就是std::function
工作方式。
這是可能的,但有點棘手。 如果我正確理解您的要求,那么您希望map
存儲的每個MyContainer
類都可能具有不同的模板專業化(例如,某些將容納std::list<int>
而另一些將容納std::list<string>
),那么您可以為地圖的值類型不再僅僅是MyContainer
,而是可以容納list<int>
和list<string>
。
正如@IanPudney所指出的,使用繼承的一種方法。
然而,你可以做到這一點,即使沒有創建繼承層次MyContainer
類,如果你不是聲明地圖作為map<string, boost::any>
(見http://www.boost.org/doc/libs/1_61_0/doc/html/ boost / any.html ),這樣您就可以在此映射中存儲任何類型的MyContainer
而無需事先創建繼承層次結構。
有兩種不使用繼承的方式來執行此操作,但這也可能取決於一些決定性因素。 第一個問題是:創建外部類的實例時,已知模板容器的類型。 如果是,那么這是一個易於編寫的類。 如果不是這樣,那么仍然可以完成,但是會涉及更多的工作。 如果不區分大小寫,則有兩種方法可以做到這一點,第一種是您不通過將其設為類模板而試圖避免的方法。 第二個涉及更多的工作,將顯示有關如何定義此類的一些邏輯。
偽代碼: -第一種情況,創建時知道類型
#include <map>
template<class T>
class MyContainer {
// ... Class Variables, Constructors & Methods
}
// For Demonstration We will say that `T` is known to be an int upon instantiation
class MyClass {
private:
std::map< std::string, MyContainer<int> > maps_;
public:
MyClass() {}
~MyClass() {
// Clear Out Map
}
void addItem( std::string& str, int value ) {
maps_.insert( std::make_pair( str, MyContainer<int>( value ) );
}
};
現在,對於第二種情況,在不使用包裝模板的情況下使用該方法不知道類型的情況下,您將需要了解此類可以支持的所有類型,並且需要為每個類型創建typedef
。
偽代碼 -類型未知的第二種情況:
#include <map>
template<class T>
class MyContainer {
// ... Class Variables, Constructors & Methods
}
// For Demonstration We will say that `T` is unknown before instantiation
class MyClass {
public:
typedef MyContainer<int> INTS;
typedef MyContainer<float> FLOATS;
typedef MyContainer<double> DOUBLES;
// And Do This For Every Type This Class Will Support.
private:
std::map< std::string, INTS > mapInts_;
std::map< std::string, FLOATS > mapFloats_;
std::map< std::string, DOUBLES > mapDoubles_;
// And You Will Need A Container For Each Supporting Type
public:
MyClass() {}
// If You Have Constructors Other Than Default That Excepts Parameter Types
// You Will Need A Constructor For Each Supporting Type
~MyClass() {
// Clear Out All Maps
}
void addInts( std::string& str, MyClass::INTS );
void addFloats( std::string& str, MyClass::FLOATS );
void addDoubles( std::string& str, MyClass::DOUBLES );
// And You Will Need A Corresponding Function For Each Type This Class Supports.
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.