【问题标题】:An std container inside a template method模板方法内的标准容器
【发布时间】:2011-02-27 19:03:50
【问题描述】:

您好。

我不太清楚如何解释自己,但我相信一段代码会让你明白我的意图:

template<class A, class B>
void myFunction(A<B>& list)
{
  typename A<B>::iterator current = list.begin();
  typename A<B>::iterator end = list.end();

  while (current != end)
  {
    current++;
  }
}

其中 A 是一个 STL 容器(向量、列表...)。这就像 inception,但是有模板:一个模板,一个模板内,等等......

问题是:当您的模板的参数之一本身就是模板时,您会怎么做......并且仍然希望支持此模板支持的所有类型。

这当然不能编译(它说“A 不是模板”)。

有人知道如何创建这样的模板吗?

【问题讨论】:

    标签: c++ templates containers std


    【解决方案1】:

    您正在寻找模板模板参数

    template<template<class T, class All = std::allocator<T> > class A, class B>
    void myFunction(A<B>& list)
    {
      typename A<B>::iterator current = list.begin();
      typename A<B>::iterator end = list.end();
    
      while (current != end)
      {
        current++;
      }
    }
    

    但是,在您的特定情况下,我认为您最好只传递实例化容器,即

    template<class C>
    void myFunction(C& list)
    {
       ...
    }
    

    这样使用

    vector<char> v;
    myFunction(v);
    

    您的原始代码必须这样调用:

    myFunction<std::vector, char> (v)
    

    更冗长,没有什么特别的好处

    【讨论】:

    • 您不能在模板模板参数中使用默认模板参数,此外,您根本不能在函数模板中使用默认模板参数。因此,模板模板参数版本必须为不同的容器和不同的默认模板参数有几个重载版本,这就是为什么它并不真正可行。
    • @Mikael:我没有在函数模板中使用默认参数。默认参数是完全合法的模板模板参数本身
    【解决方案2】:

    AB 将是具体类型(而不是模板),因此 A&lt;B&gt; 没有意义。

    您可以这样编写代码:

    template<class List>
    void myFunction(List &list)
    {
      typename List::iterator current = list.begin();
      typename List::iterator end = list.end();
    
      while (current != end)
      {
        current++;
      }
    }
    

    如果您需要知道该列表中某个元素的类型,则列表内有一个 typedef:

    typename List::value_type
    

    【讨论】:

    • +1,因为它是解决问题的最简单方法。模板模板参数很快就会变得混乱,因为它们需要数量匹配。
    【解决方案3】:

    好吧,解决这个小示例问题。这很简单。 vector&lt;int&gt; 是一个类,所以你不需要在原型中声明A&lt;B&gt;。你可以这样做:

    template<class A>
    void myFunction(A& list)
    {
      typedef typename A::value_type B; //do this if you need to know the type of the elements.
      typename A::iterator current = list.begin();
      typename A::iterator end = list.end();
    
      while (current != end)
      {
        current++;
      }
    }
    

    但如果你真的需要,你也可以将模板参数声明为模板:

    template< template<class> class A, class B >
    void myFunction(A<B>& list)
    {
      typename A<B>::iterator current = list.begin();
      typename A<B>::iterator end = list.end();
    
      while (current != end)
      {
        current++;
      }
    }
    

    但实际上并不推荐上述方法,大多数类模板都有一组嵌套的 typedef(如 STL 容器中的迭代器和 value_type),因此您可以访问所需的有关类型的所有信息,而无需使用这些模板模板参数。因此,第一种方法通常是首选且更正常的方法(使其工作起来通常也更容易,即编译器倾向于“不喜欢”模板​​模板参数)。

    此外,您不能通过模板模板参数非常轻松地使用 STL 容器,因为 STL 容器都具有这些“隐藏”模板参数(例如,“分配器”和用于排序容器的“比较”)。因此,您还必须列出所有这些,否则编译器将无法进行匹配。然后,您将不会有一个非常“通用”的功能,因为您将不得不对过去的 STL 容器做出太多假设,以至于它只能服务于一种或两种类型的容器。使用第一种方式确实更好。

    【讨论】:

    • 你不能将一个 stl 容器传递给这个方法,因为 STL 容器至少有 2 个模板参数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多