【问题标题】:C++ templates template (double template?)C++ 模板模板(双模板?)
【发布时间】:2011-06-25 11:13:39
【问题描述】:

我想构建一个Stack 类,以便用户能够选择他想使用哪个容器来实现Stack。例如,List/Vector

部分代码:

stack.h

#ifndef STACK_H_
#define STACK_H_

template <typename T, template<typename T> class ContainerType>
class Stack{
    ContainerType<T> container;
public:
    Stack() : container(ContainerType<T>()){}

};

#endif /* STACK_H_ */

test.cpp

#include "stack.h"
#include <vector>

int main(){   
    Stack<int, std::vector<int> > stack;
    return 0;
}

好吧,它不编译。我在线收到下一个错误:

Stack<int, std::vector<int> > stack;

错误:

expected a class template, got `std::vector<int, std::allocator<int> >' test.cpp

invalid type in declaration before ';' token test.cpp

type/value mismatch at argument 2 in template parameter 
list for `template<class T, template<class T> class ContainerType> 
class Stack' test.cpp

‪

【问题讨论】:

  • 这个错误是由于总是写using namespace std;并习惯它的蹩脚做法的结果。
  • @Armen 但真正的错误在其他地方。

标签: c++ templates


【解决方案1】:

首先,它将是std::vector,仅此而已,因为vector 位于std 命名空间中,并且您要求模板模板参数,而std::vector&lt;int&gt; 不是模板了。接下来,std::vector 实际上采用 两个 模板参数,一个用于类型,另一个用于分配器:

template <
    typename T,
    template<typename, typename> class ContainerType,
    typename Alloc = std::allocator<T>
>
class Stack{
  ContainerType<T, Alloc> container;
  // ...
};

// usage:
Stack<int, std::vector> s;

现在,这仅允许具有两个模板参数的容器作为底层类型,因此您最好使用标准所做的:将其作为普通类型:

template <typename T, typename ContainerType>
class Stack{
  ContainerType container;
  // ...
};

// usage:
Stack<int, std::vector<int> > s;

为确保底层类型具有相同的T,您可以做一个假的“静态断言”,或者如果您有启用 C++0x 的编译器,您可以做一个实际的静态断言:

#include <tr1/type_traits> // C++03 us std::tr1::is_same
//#include <type_traits> // C++0x, use std::is_same

template <typename T, typename ContainerType>
class Stack{
  typedef typename ContainerType::value_type underlying_value_type;
  typedef char ERROR_different_value_type[
               std::tr1::is_same<T, underlying_value_type>::value ? 1 : -1
                                         ]
  ContainerType container;
  // ...
};

这是因为如果T 与使用的容器的T 不同,它将是typedef char ERROR_different_vale_type[-1],并且不可能存在负大小的数组,这会导致编译器错误。 :) 现在,使用 C++0x,您只需 static_assert 即可:

#include <tr1/type_traits> // C++03
//#include <type_traits> // C++0x

template <typename T, typename ContainerType>
class Stack{
  typedef typename ContainerType::value_type underlying_value_type;
  static_assert(std::tr1::is_same<T, underlying_value_type>::value,
    "Error: The type of the stack must be the same as the type of the container");
  ContainerType container;
  // ...
};

为方便起见,您现在可以为常见情况指定默认模板参数:

template <typename T, typename ContainerType = std::vector<T>>
class Stack{
  ContainerType container;
  // ...
};

// usage:
Stack<int> s;

此时您可以使用std::stack,它正是这样做的(尽管它使用std::deque 作为底层类型)。 :)

【讨论】:

  • 是的,但我也希望能够编写 Stack > 堆栈,而不仅仅是向量。如果我使用你的第二个代码块,如果我使用会发生什么: Stack > stack.它会只是一个双向量吗?我可以做一个约束,使向量的类型为 int 而不是 double(我的意思是它会像第一种类型)?
  • @user550413:如果你写Stack &lt;int, List&gt;,那么容器类型将是List&lt;int&gt;,就像Stack &lt;int, vector&gt;得到vector时一样。
  • 非常感谢。我在定义复制构造函数时遇到问题?
  • @user:到底是什么?如果它与这个问题无关,请打开一个新问题! :)
  • 可变参数模板有助于解决模板数量问题:en.wikipedia.org/wiki/Variadic_template
【解决方案2】:

最简单的方法是不使用模板模板参数,因为容器的数量问题。

相反,只需传递完整的容器类型,仅此而已。然后提取value_type(标准STL内部typedef)得到值。

template <typename Container>
class Stack
{
public:
  typedef typename Container::value_type value_type;

private:
  Container _container;
}; // class Stack<Container>

然后,您可以简单地将其用作Stack&lt; std::vector&lt;int&gt; &gt;,它将包含ints。

【讨论】:

    【解决方案3】:

    由于vector 属于std 命名空间,您必须对其进行限定。但除此之外,ContainerType 是模板模板参数,您需要传递模板而不是最终类型:

    Stack<int, std::vector > stack;
    

    【讨论】:

      【解决方案4】:

      这一行:

           Stack<int, vector<int> > stack;
      

      应该是:

        Stack<int, std::vector<int> > stack;
      

      或者你可以在 test.cpp 前面加上

       using namespace std;
      

      【讨论】:

      • 当他只需要using std::vector时,为什么要引入整个命名空间std?
      • @user550413 看看其他答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-05
      • 1970-01-01
      • 2012-12-06
      相关资源
      最近更新 更多