对于函数模板和类模板,模板参数并不局限于类型,普通值也可以作为模板参数。在基于类型参数的模板中,定义一些具体细节未加确定的代码,直到代码被调用时这些细节才被真正确定。然而,在这里,我们面对的这些细节是值(value),而不是类型。当要使用基于值的模板时,你必须显式地指定这些值,才能够对模板进行实例化,并获得最终代码。
较之前的Stack例子的实现,可以使用元素数目固定的数组来实现Stack。这个方法(用固定大小的数组)的优点是:无论是由你来亲自管理内存,还是由标准容器来管理内存都可以避免内存管理开销。然而,决定一个栈(stack)的最佳容量是很困难的。如果你指定的容量太小,那么栈可能会溢出;如果指定的容量太大,那么可能会不必要地浪费内存。一个好的解决方法就是:让栈的用户亲自指定数组的大小,并把它作为所需要的栈元素的最大个数。
例如:
//stack4.h
#ifndef STACK4_H
#define STACK4_H
#include <stdexcept>
#include <iostream>
template<typename T, int MAXSIZE>
class Stack {
private:
T elems[MAXSIZE]; //包含元素的数组
int numElems; //无素的当前总个数
public:
Stack(); //构造函数
void push(T const &elem); //压入元素
void pop(); //弹出元素
T top() const; //返回栈顶元素
bool empty() const { //返回栈是否为空
return numElems == 0;
}
bool full() const { //返回栈是否已满
return numElems == MAXSIZE;
}
};
//构造函数
template <typename T, int MAXSIZE>
Stack <T, MAXSIZE>::Stack()
:numElems(0) //numElems初始化为0
{
std::cout << "constructor==========Stack===========" << std::endl;
}
template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::push(T const &elem)
{
if(numElems == MAXSIZE) {
throw std::out_of_range("Stack<>::push(): stack is full");
}
elems[numElems] = elem; //附加元素
++numElems; //增加元素的个数
}
template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::pop()
{
if(numElems <= 0) {
throw std::out_of_range("Stack<>::pop(): empty stack");
}
--numElems; //减少元素的个数
}
template <typename T, int MAXSIZE>
T Stack<T, MAXSIZE>::top() const
{
if(numElems <= 0) {
throw std::out_of_range("Stack<>::top(): empty stack");
}
std::cout << "top()=====numElems=====" << numElems << std::endl;
return elems[numElems - 1]; //返回最后一个元素
}
#endif // STACK4_H
为了使用这个类模板,你需要同时指定元素的类型和个数(即栈的最大容量)
//stack4test.cpp
#include <iostream>
#include <string>
#include <cstdlib>
#include "stack4.h"
int main()
{
try {
Stack<int, 20> int20Stack; //可以存储20个int元素的栈
Stack<int, 40> int40Stack; //可以存储40个int元素的栈
Stack<std::string, 40> stringStack;//可存储40个string元素的栈
//使用可存储20个int元素的栈
int20Stack.push(89);
std::cout << int20Stack.top() << std::endl;
int20Stack.pop();
//使用可存储40个string的栈
stringStack.push("hello");
std::cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
} catch (std::exception const &ex) {
std::cerr << "Exception: " << ex.what() << std::endl;
return EXIT_FAILURE; //退出程序且有ERROR标记
}
return 0;
}
运行结果: