一 概念:
产生模板的特定类型实例的过程称为 实例化。包括: 类模板的实例化和 函数模板的实例化。
二 类模板实例化
要使用类模板必须 显示指定模板形参。在类模板的 内部使用时,可以使用类模板的非限定名。
例如:
template<typename T>
class Queue
{
public:
Queue(){}
Queue(Queue &Q):a(Q.a){}// 等价于Queue<Type>(Queue<Type> &Q):a(Q.a){} 不使用类模板限定。
private:
int a;
};
Queue <string>queue;
实际上,当编写Queue<int>时,编译器通过重新编写Queue模板,用类型int代替模板形参的每次出现而 创建Queue<int>类。
三 函数模板实例化
使用函数模板时,编译器通常会 推断模板实参。
四 模板实参推断(template argument deduction)
模板实参推断: 从函数实参确定模板实参的类型和值的过程。
1.多个类型形参的实参 必须完全匹配
例如:
template<typename T>
void test1(T &t1,T &t2)
{
cout<<t1<<"\n"<<t2<<endl;
}
调用:
int t1=1;
short int t2=2;
test1(t1,t2);// 错误,形参与实参类型完全匹配,不允许常规转换。
如果需要常规转化:函数必须用两个类型形参来定义。
template<typename T1,typename T2>
void test1(T1 &t1,T2 &t2)
{
cout<<t1<<"\n"<<t2<<endl;
}
2. 类型形参的实参的 受限转换
一般而言,不会转换实参以匹配已有的实例化,相反,会产生新的实例。
除了产生新的实例外,编译器只执行两种转换:
const转换:可以用非const对象的指针或引用来调用接受const指针或const引用的函数;如果函数接受非引用形参,形参类型和实参类型都忽略const。
数组或函数到指针的转化:如果模板形参不是引用类型,则对数组和函数类型的实参应用常规指针转换。
五 函数模板的 显式形参
在某些情况下,不可能推断模板实参的类型,那么就有必要覆盖模板实参推断机制,并显式指定为模板形参所用的类型或值。
六 非类型模板形参和 非模板形参
1. 非类型模板形参:模板形参不必都是类型。
函数模板非类型形参和类模板非类型形参: 在需要常量表达式时可以使用非类型形参,非类型实参必须是常量表达式