通过template <typename T, class C,…(模板参数列表)>
来定义模板
class
关键字和 typename
关键字没有任何区别
只是后者从名字上来说更清晰 出现的更晚而已
模板参数列表中除了定义类型参数 还可以定义非类型参数
其中的非类型参数表示一个值而非一个类型
而当一个模板被实例化时 非类型参数必须被一个用户提供的或是编译器推断的常量表达式替代
// 我们在模板参数列表中定义了两个非类型参数 其类型为无符号整数
// 用于指定比较的字符串长度
template<unsigned int N, unsigned int M>
int compare(const char (&p1)[N], const char (&p1)[M]){
return strcmp(p1,p2);
}
// 我们调用这个版本的compare时 编译器根据字面常量的大小来推断N和M的值
// 注意 编译器会为字面常量的字符串末尾自动插入\0作为终止符
compare("hi","hello");
// 因此 编译器最终会为上面的调用实例化出下面的版本
int compare(const char (&p1)[3], const char (&p1)[6]);
将函数模板声明为inline
或constexpr
时 其定义说明符跟在模板参数列表之后 返回类型之前
Template<typename T> inline T min(cosnt T&, cosnt T&);
大多数模板的错误在实例化期间才报告
使用类模板时 必须通过显式模板实参列表来提供额外信息
但在类自身内部的作用域中 可以直接使用模板名而不提供实参
一个类模板的每个实例都生成一个独立的类 互相之间没有任何关系
当一个类模板包含一个非模板友元 则该友元可以访问所有模板实例
如果友元自身是模板 类可以授权给所有模板实例 也可以只授权给特定实例
Template<typename T> class C{
Friend class pal<C>; //只有用类C实例化的类pal是C的友元
Template <typename X> friend class pal2;
// 所有类pal的实例化都是C的友元 注意必须使用不同的模板参数
};
这种情况下可以用typename
关键字告诉编译器一个名字表示类型 但不能用class
即使所有的模板参数都定义了默认实参 但定义时仍然必须有个<>
Numbers<> a;