和往常一样,先来看一段代码:
#include <stdexcept> template <typename T, int MAXSIZE> class Stack { private: T elems[MAXSIZE]; // elements int numElems; // current number of elements public: Stack(); // constructor void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const { // return whether the stack is empty return numElems == 0; } bool full() const { // return whether the stack is full return numElems == MAXSIZE; } }; // constructor template <typename T, int MAXSIZE> Stack<T,MAXSIZE>::Stack () : numElems(0) // start with no elements { // nothing else to do } 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; // append element ++numElems; // increment number of elements } template<typename T, int MAXSIZE> void Stack<T,MAXSIZE>::pop () { if (numElems <= 0) { throw std::out_of_range("Stack<>::pop(): empty stack"); } --numElems; // decrement number of elements } template <typename T, int MAXSIZE> T Stack<T,MAXSIZE>::top () const { if (numElems <= 0) { throw std::out_of_range("Stack<>::top(): empty stack"); } return elems[numElems-1]; // return last element }
接下来编写我们的测试函数:
#include <iostream> #include <string> #include <cstdlib> #include "stack4.hpp" int main() { try { Stack<int,20> int20Stack; // stack of up to 20 ints Stack<int,40> int40Stack; // stack of up to 40 ints Stack<std::string,40> stringStack; // stack of up to 40 strings // manipulate stack of up to 20 ints int20Stack.push(7); std::cout << int20Stack.top() << std::endl; int20Stack.pop(); // manipulate stack of up to 40 strings 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; // exit program with ERROR status } }
大家要注意int20Stack和int40Stack是两个不同的类型,他们是不能进行硬是或者显示的转换的。也不能够相互赋值。
你还可以为函数模板定义非型别参数:
template <typename T, int VAL> T addValue (T const& x) { return x + VAL; }
当我们想把【函数】和某种操作作为参数传递的时候,就非常有用,比如在使用STL时,你可能有下面的代码:
std::transform (source.begin(), source.end(), // start and end of source dest.begin(), // start of destination addValue<int,5>); // operation
std::transform (source.begin(), source.end(), // start and end of source dest.begin(), // start of destination (int(*)(int const&)) addValue<int,5>); // operation
但是我们要注意,非类型模板参数也有自己的局限,通常来说他们只能是常整数,包括枚举,或者指向外部链接的指针。如果我们用浮点数或者class-type objects作为非类型模板参数是错误的:
template <double VAT> // ERROR: floating-point values are not double process (double v) // allowed as template parameters { return v * VAT; } template <std::string name> // ERROR: class-type objects are not class MyClass { // allowed as template parameters … };
由于字串字面常熟是一种采用内部链接的物件,也就是说不通模组中的两个同值的字串字面常数其实是两个不同的东西,所以他们也不能用来作为模板参数:
template <char const* name> class MyClass { … }; MyClass<"hello"> x; // ERROR: string literal "hello" not allowed
此外全局指针也是不行的:
template <char const* name> class MyClass { … }; char const* s = "hello"; MyClass<s> x; // ERROR: s is pointer to object with internal linkage
但是下面的例子是可以的:
template <char const* name> class MyClass { … }; extern char const s[] = "hello"; MyClass<s> x; // OK
在这个例子中,s是一个外部连接的部件。