【问题标题】:Template definition with template template parameter for class that can specialize, for instance, to std::vector<std::string> or std::map<std::tree>具有模板模板参数的模板定义,用于可以专门化的类,例如 std::vector<std::string> 或 std::map<std::tree>
【发布时间】:2018-01-30 08:53:56
【问题描述】:

我想创建一个可以容纳容器和容器的任意组合的模板类。例如,std::vector&lt;std::string&gt;std::map&lt;std::tree&gt;

我尝试了很多组合,但我必须承认模板的复杂性让我不知所措。我编译的关闭是这样的:

template <class Vector, template <typename, class Containee = std::string> class Container>
class GenericContainer
{
    Container<Containee> mLemario;
};

虽然到目前为止它已编译,但是当我想实例化它时,我收到很多错误。

MyContainer<std::vector, std::string> myContainer;

我是否使用正确的方法来创建这种类?

【问题讨论】:

  • 没有std::map&lt;std::tree&gt;这样的东西,因为(1)没有std::tree和(2)std::map需要(至少)两个参数:keyvaluestd::map&lt;key,value&gt;。那么你认为std::map 的容器是什么?它的key,或者它的value,或者std::pair&lt;key,value&gt;(这实际上是std::map::value_type给你的)?
  • 它将支持什么功能?你打算怎么用?问是因为不同的容器提供了非常不同的功能和不同的复杂性。它们不能互换。总的来说,我认为这是一个坏主意。

标签: c++ templates vector stl


【解决方案1】:

标准容器为其元素类型声明名称,因此您可以编写

template<typename Container>
class GenericContainer
{
    using Containee = typename Container::value_type;
};

你可以这样使用它:

int main()
{
    GenericContainer<std::vector<std::string>> myContainer;
}

您可以对此类容器使用非默认分配器,但不要轻易创建具有不同元素类型的类似容器。这对你来说可能是也可能不是障碍。

【讨论】:

  • 我想你的意思是Container::value_type
  • 不完全是我想要的,因为我希望 std::string 也是一个参数
  • @HolaMundo 首先,你没有指定这个。其次,您可以轻松创建处理该问题的模板别名声明。
  • 感谢@Walter 的编辑 - 我应该多加小心!
  • @HolaMundo 是的,但是像std::vector&lt;std::string&gt; 这样的类型已经是一个容器和容器
【解决方案2】:

对于std::vector(等等)@songyuanyao 提供了一个很好的答案。但既然你也提到了std::map,我将添加一个简单的扩展@songyuanyao的答案online

#include <iostream>
#include <vector>
#include <string>
#include <map>

template <template <typename...> class Container, typename Containee = std::string, typename... extras>
class GenericContainer
{
    Container<Containee, extras ...> mLemario;
    // Use 'Containee' here (if needed) like sizeof(Containee) 
    // or have another member variable like: Containee& my_ref.
};

int main()
{
    GenericContainer<std::vector, std::string> myContainer1;
    GenericContainer<std::vector, std::string, std::allocator<std::string>> myContainer2; // Explicitly using std::allocator<std::string>
    GenericContainer<std::map, std::string, int> myContainer3; // Map: Key = std::string, Value = int
}

【讨论】:

  • 太棒了!正如我所料,这不适合初学者。它编译到现在。
  • 我发现在模板声明之外实例化一个函数非常困难:我正在尝试这样的事情: template
  • 看看这里:cpp.sh/94kih。如果这没有帮助,请告诉我。如果它变得非常复杂,那么也许会问一个新问题。
  • 它有效。我将为我的最后一个愿望创建另一个问题:函数专业化
  • -1 这是一个糟糕的建议/设计:Containee 不需要作为template 参数,因为它很容易被称为Container::value_type。类似地,extras 也不需要,因为它隐含在 Container 中(并且不会在您的类中的任何地方使用)。
【解决方案3】:

我想创建一个可以容纳容器和容器的任意组合的模板类

您应该将parameter pack 用于模板模板参数ContainerContainee,然后它们可以与任意数量/类型的模板参数一起使用。例如

template <template <typename...> class Container, typename... Containee>
class GenericContainer
{
    Container<Containee...> mLemario;
};

然后

GenericContainer<std::vector, std::string> myContainer1;
GenericContainer<std::map, std::string, int> myContainer2;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多