非类型的类模板参数
template<typename T, int MAX_SIZE> // MAX_SIZE不是类型,也可以作为模板参数
class Stack
{
private:
T elems[MAX_SIZE];
int numElems;
public:
Stack();
void push(T const&);
void pop();
T top() const;
bool empty() const{
return numElems == 0;
}
bool full() const{
return numElems == MAX_SIZE;
}
}
template<typename T, int MAX_SIZE>
Stack<T, MAX_SIZE>::Stack(): numElems(0)
{
}
template<typename T, int MAX_SIZE>
void Stack<T, MAX_SIZE>::push(T const& elem)
{
elems[numElems] = elem;
numElems++;
}
....略
// 使用
Stack<int, 20> int20Stack;
Stack<int, 40> int40Stack;
// 也可以使用缺省值
template<T, int MAX_SIZE = 20>
class Stack
{
}
Stack<int> intStack; // Stack<int, 20>
注意:非类型的模板参数不同也是不同的类型,Stack<int, 20>和Stack<int, 40>是不同的类型
非类型的函数模板参数
template<typename T, int VAL>
T addValue(T const& x)
{
return x + VAL;
}
// 也可以使用缺省值
template<typename T, int Val = 5>
T addValue(T const& x)
{
return x + VAL;
}
非类型模板参数的限制
合法:常整数(包括枚举值),指向外部链接对象的指针
非法:浮点数(历史遗留,估计是浮点数的精确度原因),类对象
不能使用字符串
template<char const* name>
class MyClass
{
...
}
// 1.cpp
MyClass<"hello"> s; // 错误,“hello”为内部对象
// 2.cpp
MyClass<"hello"> s; // 错误,“hello”为内部对象
1.cpp和2.cpp中的“hello”处于不同的编译单元,是不同的对象,因此1.cpp和2.cpp都会实例化MyClass。因为整数可以直接比较值,但是字符串应该会转换为指针,会发生相同的字符串实例化为多个不同的模板实例的情况。
不能使用全局指针
template<char const* name>
class MyClass
{
...
}
char const* s = "hello"; // 全局指针在不同的编译单元也是不同的对象
MyClass<s> x; // ERROR
extern char const* s = "hello"; // extern修饰为外部指针,指向同一对象。
MyClass<s> x; // OK
理解:整数可以直接比较大小,外部链接指针指向相同的对象,都不会发生两个相同值的非类型模板实参产生多个模板实例。而浮点数和类对象会有这种可能。