对于函数模板与类模板,模板参数并不局限于类型,普通值也可以作为模板参数。在基于类型参数的模板中,你定义了一些具体的细节来加以确定代码,直到代码被调用时这些细节才被真正的确定。但是在这里,我们面对的是这些细节是值,而不是类型,当要使用基于值的模板时,必须显式地指定这些值,才能够对模板进行实例化。
非类型的类模板参数
创建类的头文件
#include<stdexcept> #include<iostream> using namespace std; template<typename T, int MAXSIZE> class Stack{ private: T elems[MAXSIZE]; int numElems; public: Stack(); void push(T const&); 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) {} template<typename T, int MAXSIZE> void Stack<T, MAXSIZE>::push(T const& elem) { if(numElems == MAXSIZE) { throw 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 out_of_range("Stack<>::pop(): stack is full"); } --numElems; } template<typename T, int MAXSIZE> T Stack<T, MAXSIZE>::top() const { if(numElems <= 0) { throw out_of_range("Stack<>::top(): stack is full"); } return elems[numElems - 1]; }
#include<stdexcept> #include<iostream> using namespace std; template<typename T, int MAXSIZE> class Stack{ private: T elems[MAXSIZE]; int numElems; public: Stack(); void push(T const&); 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) {} template<typename T, int MAXSIZE> void Stack<T, MAXSIZE>::push(T const& elem) { if(numElems == MAXSIZE) { throw 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 out_of_range("Stack<>::pop(): stack is full"); } --numElems; } template<typename T, int MAXSIZE> T Stack<T, MAXSIZE>::top() const { if(numElems <= 0) { throw out_of_range("Stack<>::top(): stack is full"); } return elems[numElems - 1]; }
实现代码:
#include<iostream> #include<vector> #include<deque> #include<stdexcept> #include<string> #include<cstdlib> #include "stack4.h" using namespace std; int main() { try { Stack<int, 20> int20Stack; Stack<int, 40> int40Stack; Stack<string, 40> stringStack; int20Stack.push(7); cout<<int20Stack.top()<<endl; int20Stack.pop(); stringStack.push("hello"); cout<<stringStack.top()<<endl; stringStack.pop(); stringStack.pop(); } catch(exception const& ex) { cerr<<"Exception: "<<ex.what()<<endl; //return EXIT_FAILURE; } cin.get(); return 0; }
#include<iostream> #include<vector> #include<deque> #include<stdexcept> #include<string> #include<cstdlib> #include "stack4.h" using namespace std; int main() { try { Stack<int, 20> int20Stack; Stack<int, 40> int40Stack; Stack<string, 40> stringStack; int20Stack.push(7); cout<<int20Stack.top()<<endl; int20Stack.pop(); stringStack.push("hello"); cout<<stringStack.top()<<endl; stringStack.pop(); stringStack.pop(); } catch(exception const& ex) { cerr<<"Exception: "<<ex.what()<<endl; //return EXIT_FAILURE; } cin.get(); return 0; }
MAXSIZE是新加入的第二个模板参数,类型为int,它指定了数组最多可包含的栈元素的个数
同样,我们可以为模板参数指定缺省值:
template<typename T = int, int MAXSIZE = 100> class Stack { ... };
非类型的函数模板参数
你也可以为函数模板定义非类型参数。例如:
template<typename T, int VAL> T addValue(T const& x) { return x + VAL: }
借助于STL,可以传递这个函数模板的实例化给集中的每一个元素,让他们都增加一个整数值:
std::transform(source.begin(), source.end(), dest.begin(), (int(*)(int const&))addValue<int, 5>);
非类型模板参数的限制
非类型模板参数是有限制的,通常而言,它们可以是常整数(包括枚举值)或者指向外部链接对象的指针。
浮点数和类对象是不允许作为非类型模板参数的:
template<double VAT> double process(double v) //error { return V * VAT; } template<string name> //error class MyClass { ... };
另外,你也不能使用全局指针作为模板参数:
template<char const* name> class MyClass{ ... }; char const* s = "hello"; MyClass<s> x; //s是一个指向内部连接对象的指针
但是你可以这样使用:
template<char const* name> class MyClass { ... }; extern char const s[] = "hello"; MyClass<s> x; //OK
全局字符数组s由"hello"初始化,是一个外部链接对象