摘要:
1)template parameters不限只能是类型,也可以是数值;
2)不能将浮点数(历史原因)、class-type对象、内部链接对象当做nontype template parameters的自变量。
非类型模板参数
本篇博文中以创建一个固定大小的Stack为例,来加以理解非类型模板参数:
#include <stdexcept>
template <typename T,int MAXSIZE>
class Stack{
private:
T elems[MAXSIE];
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 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.");
}
return elems[numElems-1];
}
#include <iostream>
#include <string>
#include <cstdlib>
#include "stack.hpp"
int main(){
try{
Stack<int,20> int20Stack;
Stack<int,40> int40Stack;
Stack<std::string,40> stringStack;
int20Stack.push(7);
std::cout<<int20Stack.top<<std::endl;
int20Stack.pop();
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;
}
}
需要注意的是,每一个被实例化的class template都有各自的类型,因此int20Stack和int40Stack是两个不同的乐行,不能互相进行隐式类型转换,更不能互相赋值。
我们也可以给non-type template parameters设定默认值:
template <typename T=int,int MAXSIZE=100>
class Stack{
...
}
Nontype Function Template Parameter
template <typename T,int VAL>
T addValue(T const& x){
return x+VAL;
}
当我们需要将函数或者某种通用操作作为参数传递时,这一类型就非常有用,如我们可以运用上述的function template的实例,将某值加到元素集内的每一个元素升上:
std::transform(source.begin(),source.end(),dest.begin(),addValue<int,5>);
但上述的代码中存在问题,addValue
std::transform(source.begin(),source.end(),dest.begin(),(int(*)(int const*)) addValue<int,5>);
Nontype Template Parameter的局限性
Nontype Template Parameters可以使用整型类型、enum、指向外部链接的指针或者引用,同时不能把普通局部对象或者动态对象绑定到指针或者引用的非类型模板参数上面,以及全局指针也不可以,可以使用全局类型绑定,因为绑定非类型模板参数的形参必须是常量表达式。
以浮点数或者class-type objects作为nontype template parameters是不可以的。
template <char const* name>
class MyClass{
...
};
MyClass<"hello"> x;//错误,不能使用字符串变量“hello”
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