我们可以用C++中的非模板类“包装”模板类吗?

问题描述:

声明:恐怕我的问题的简短答案是“不可能的”。但是因为我不是C++专家,所以我仍然试着在这里问一下,也许有某种解决方案我只是不知道。我们可以用C++中的非模板类“包装”模板类吗?

所以我有模板容器类MyContainer内部存储数据在std::list<T>,其中T是类模板类型。这工作正常。

现在我想添加另一个类,它必须映射std::map<std::string, MyContainer>中的模板容器类的实例。但是,编译器要求我为地图的值部分提供模板类类型,如std::map<std::string, MyContainer<T>>中所述。但是我宁愿在这里省略这个模板,因为这反过来又要求我也为包装类使用模板。

因此,我的问题:有没有办法实现我想要做的,省略包​​装类的模板类型,至少在某种程度上?或者这在C++中是不可能的,因为编译器在任何情况下都需要这些信息?

+8

有作为“模板类”没有这样的事。 C++有类模板。类模板不是类。你的描述很不明确。请显示更多你的代码。 –

这样做的一种常见技术是继承。

使MyContainer<T>继承自某个基类,如MyBaseContainerMyBaseContainer不是模板类,但是MyContainer是。 MyBaseContainer类具有模板类覆盖的虚拟函数。

然后,您将制作您的std::map<std::string, MyBaseContainer*>类型的地图。它将能够在其存储的容器上调用虚函数,而不必知道每个容器的模板类型。

这就是std::function的工作原理。

+0

啊,这很有道理。谢谢! – Matthias

+1

这里唯一的问题是MyBaseContainer不能有太多有用的虚函数。 –

+0

如果你绝对必须,你也可以在'MyBaseContainer'指针上使用'dynamic_cast *>()'(或者在某些情况下甚至是'static_cast')。但是,这是一个非常丑陋的设计。 – microtherion

这是可能的,但有点棘手。如果我正确地理解了你,你希望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存储这个地图里面,而不需要创建继承层次提前。

+0

感谢您分享这个想法。我宁愿不使用boost lib(或任何其他第三方lib)。 – Matthias

有两种可能的方式来做到这一点,而不使用继承,但这也可能取决于一些决定因素。第一个问题是:在创建外部类的实例时,已知的是模板容器的类型。如果是的话,这是一个容易写作的课程。如果不是,那么仍然可以完成,但会涉及更多的工作。如果案例不知道,有两种方法可以做到这一点,第一种方法是通过不制作这个类模板来避免这种情况。第二个涉及更多的工作,其中一些关于如何定义这个类的逻辑将被显示。

伪代码: - 1种情况,其中类型是已知的在创建现在

#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

伪码 - 2情况如果不知道类型:

#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. 

};