模板形参包含:类型形参,非类型形参
模板实参推断(p538):一般而言,不会转换实参以匹配已有的实例化,相反,会产生新的实例。除了产生新的实例化之外,编译器只会执行两种转换:
类型形参:
声明:typename(或class) T(标识符)
使用时:具体类型如int
非类型形参:
声明:类型说明符(如int,size_t)
使用时:常量表达式(如16)
编写模板代码需注意:
1)模板形参不能为空
2)每个模板类型形参前面必须带上关键字class或typename,每个非类型形参前面必须带上类型名字,省略关键字或类型说明符是错误的
eg:template <typename T,U> T calc(const T&,const U&);
//error
模板形参表中,关键字typename和class具有相同含义,使用关键字typename更为直观,毕竟它也能表示内置类型
在模板定义内部指定类型:
template <class Param,class U>
Parm fcn(Param *array,U value)
{
Parm::size_type *p; //如果size_type是个类型,则此句为声明一个指针类型
//如果size_type是个对象,则此句为一个乘法表达式
}
默认情况下,编译器假定这样的名字指定数据成员(即对象),而不是类型
通过在
成员名前加上关键字typename作为前缀,可以告诉编译器将成员当做类型:typename Parm::size_type *p;当然这一声明给用来实例化fcn的类型增加一个职责:那些类型必须具有名为size_type的成员,而且该成员是一个类型
注意:如果拿不准是否需要以typename指明一个名字是一个类型,那么指定它是个好主意。在类型之前指定typename没有害处,因此,即使typename是不必要的,也没有关系
函数模板可以用非模板函数一样的方式声明为inline。说明符放在模板形参表之后,返回类型之前,不能放在关键字template之前
template <typename T> inline T min(const T&,const T&);
模板实参推断(p538):一般而言,不会转换实参以匹配已有的实例化,相反,会产生新的实例。除了产生新的实例化之外,编译器只会执行两种转换:
1)const转换:
2)数组或函数到指针的转换
p547使用模板的名字的时候,必须指定模板形参。这一规则有个例外:在类本身的作用域内部,可以使用类模板的非限定名。
例如:Queue (const Queue &Q)= Queue<Type>(const Queue<Type &Q),在这里对类成员函数名和该函数的本类型的参数(注意一定要是本类型),自动会加上模板形参
编译器不会为类中使用的其他模板的模板形参进行这样的推断,因此,在声明伙伴类QueueItem的指针时,必须指定类型形参:
QueueItem<Type> *head;