一个 模板参数 本身也可以是个 类模板。我们还是以Stack<T>为例子
为了使用其它类型的元素容器,stack class 使用者必须两次指定元素类型:一次是元素类型本身, 另一次是容器类型
Stack<int,std::vector<int> > vStack; // int stack,以 vector为容器
如果使用 template template parameter,就可以只指明元素类型,无须再指定容器类型:
Stack<int,std::vector> vStack; // int stack,以 vector为容器
为了实现这种特性,我们必须把第二个 template parameter 声明为 template template parameter。
原 则上程序代码可以写为:
// basics/stack7decl.cpp
template <typename T,
template <typename ELEM> class CONT = std::deque >
class Stack {
private:
CONT<T> elems; // 元素
public:
void push(T const&); // push 元素
void pop(); // pop 元素
T top() const; // 传回 stack 顶端元素
bool empty() const { // stack 是否为空
return elems.empty();
}
};
与先前的 stack 差别在于,第二个 template parameter 被声明为一个 class template:
template <typename ELEM> class CONT
注意:CONT定义的是一个 class 类型,因此
必须使用关键词 class
来声明它。所以,下面代码是
错误的
template <typename T,
template <typename ELEM> typename CONT = std::deque > //ERROR
class Stack {
、、、
}
类的成员函数也必须按此原则修改:必须指定其第二个template parameter为template template parameter。同样的规则也适用于成员函数的实作部份。例如成员函数 push()应该实作如下:
template <typename T, template <typename> class CONT>
void Stack<T,CONT>::push (T const& elem)
{
elems.push_back(elem); // 追加元素
}
这就完成了吗?如果你试图使用上述新版 Stack,编译器会报告一个错误
严重性 代码 说明 项目 文件 行 禁止显示状态
错误(活动) E0999 类模板 "std::deque" 与 模板 template 参数 "CONT" 不兼容
问题出在 template template argument 不但必须是个 template, 而且其参数必须严格匹配它所替换的 template template parameter 的参数。标准库中的 std::deque template 要求
不只一个参数
。第二参数是个配置器(allocator),它虽有默认值,但当它被用来匹配CONT 的参数时,其默认值会被编译器强行忽略了。
正确的代码如下所示
template <typename T,
template <typename ELEM,
typename ALLOC = std::allocator<ELEM> >class CONT = std::deque>
class Stack {
private:
CONT<T> elems; // 元素
...
};
由于 ALLOC并未在程序代码中用到,或者你也可以把它省略掉。 |
template <typename T,
template <typename ELEM,typename = std::allocator<ELEM> >class CONT = std::deque>
class Stack {
private:
CONT<T> elems; // 元素
public:
...
}
最终的代码:
#ifndef STACK_HPP
#define STACK_HPP
#include <deque>
#include <stdexcept>
#include <memory>
template <typename T,
template <typename ELEM,
typename = std::allocator<ELEM> >
class CONT = std::deque>
class Stack {
private:
CONT<T> elems; // 元素
public:
void push(T const&); // push 元素
void pop(); // pop 元素
T top() const; // 传回 stack 的顶端元素
bool empty() const { // stack 是否为空
return elems.empty();
}
// 赋予一个「元素类型为 T2」的 stack
template<typename T2,
template<typename
ELEM2,
typename = std::allocator<ELEM2>
> class CONT2>
Stack<T, CONT>& operator= (Stack<T2, CONT2> const&);
};
template <typename T, template <typename, typename> class CONT>
void Stack<T, CONT>::push(T const& elem)
{
elems.push_back(elem); // 追加元素
}
template<typename T, template <typename, typename> class CONT>
void Stack<T, CONT>::pop()
{
if (elems.empty()) {
throw std::out_of_range("Stack<>::pop(): empty stack");
}
elems.pop_back(); // 移除最后一个元素
}
template <typename T, template <typename, typename> class CONT>
T Stack<T, CONT>::top() const
{
if (elems.empty()) {
throw std::out_of_range("Stack<>::top(): empty stack");
}
return elems.back(); // 传回最后一个元素的拷贝
}
template <typename T, template <typename, typename> class CONT>
template <typename T2, template <typename, typename> class CONT2>
Stack<T, CONT>&
Stack<T, CONT>::operator= (Stack<T2, CONT2> const& op2)
{
if ((void*)this == (void*)&op2) { // 是否赋值给自己
return *this;
}
Stack<T2, CONT2> tmp(op2); // 创建 assigned stack的一份拷贝
elems.clear(); // 移除所有元素
while (!tmp.empty()) { // 复制所有元素
elems.push_front(tmp.top());
tmp.pop();
}
return *this;
}
#endif // STACK_HPP
使用
int main()
{
try {
Stack<int> intStack; // stack of ints
Stack<float> floatStack; // stack of floats
// 操控 int stack
intStack.push(42
);
intStack.push(7)
;
// 操控 float stack
floatStack.push(7.7);
// 赋予一个「不同类型」的 stack
floatStack = intStack;
// 打印 float stack
std::cout << floatStack.top() << std::endl;
floatStack.pop();
std::cout << floatStack.top() << std::endl;
floatStack.pop();
std::cout << floatStack.top() << std::endl;
floatStack.pop();
}
}