簡體   English   中英

我們可以用C ++中的非模板類“包裝”模板類嗎?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM