C++ 模板模板(双模板?)
Posted
技术标签:
【中文标题】C++ 模板模板(双模板?)【英文标题】:C++ templates template (double template?) 【发布时间】: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 但真正的错误在其他地方。
【参考方案1】:
首先,它将是std::vector
,仅此而已,因为vector
位于std
命名空间中,并且您要求模板模板参数,而std::vector<int>
不是模板了。接下来,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
作为底层类型)。 :)
【讨论】:
是的,但我也希望能够编写 StackStack <int, List>
,那么容器类型将是List<int>
,就像Stack <int, vector>
得到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< std::vector<int> >
,它将包含int
s。
【讨论】:
【参考方案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 看看其他答案。以上是关于C++ 模板模板(双模板?)的主要内容,如果未能解决你的问题,请参考以下文章