模板参数分两种:
- 类型参数(type parameter)
- 前面有typename、class修饰的模板参数。typename和class可以互换,建议就用typename,因为有些特殊语法只能typename。
- 非类型参数(nontype parameter),必须是常量表达式。
- 可以是整型的,必须是常量表达式。
- 可以是指针、左值引用,对象必须是全局的、static的。 ```cpp
// 模板参数列表: <>里面逗号分隔,不能为空。里面是模板参数,分多种类型:
// 1.类型参数,前面有typename/class修饰的叫做类型参数(模板类型参数)。
// class 和typename可互换,一般用typename
// 2.非类型参数,用一个具体的类型名,不用typename/class修饰。
// 1、整型,必须是常量表达式constexpr。
// 2、指针或(左值)引用。对象必须是全局的/static的。
template
```cpp// T: 类型参数,一般也叫模板类型参数// N, M:非类型模板参数,template<typename T, unsigned N, unsigned M>int compare(const T (&arr1)[N], const T (&arr2)[M]){......}compare("hi", "mom");// 编译器在编译阶段推断出模板参数如下:// T: char// N: 3// M: 4// 正确,inline、constexpr说明符跟在模板参数列表之后template<typename T>inline T min(const T&, const T&);// 错误,inline说明符的位置不正确inline template <typename T> T min(const T&, const T&);
作用域
遵循普通的作用域规则。如果名字冲突,则隐藏外层作用域中的相同名字。
typedef double T;// 正常的名字隐藏规则决定了上面的T被隐藏。template<typename T> // 模板参数名字T可以随便取但不能重复void calc(const T& a, const T& b){T c; // T是模板参数,而非double}
访问T的成员
访问模板类型参数 T 的成员。
template<typename T>void fuck(const T& ){T::size_type *p;// 有两种语义。// 语义一:静态成员size_type 乘以 p// 语义二:声明定义size_type类型指针。}
如何让编译器认为我们是采用语义二的意思?在访问成员前面显式加上typename关键字,不能是class。
// 以下模板函数返回T的尾元素,若为空,则创建一个T存储的元素类型的元素。template <typename T>typename T::value_type top(const T& c){if (!c.empty())return c.back();elsereturn typename T::value_type();}
默认实参
模板参数列表也可以有默认实参,和函数默认实参一样,右侧参数必须都有默认实参。
// ***********************************************************// 模板函数默认实参。// ***********************************************************template <typename T , typename F = less<T>>int compare(const T &v1, const T &v2, F f = F()){if (f(v1, v2)) return -1;if (f(v2, v1)) return 1 ;return 0;}compare(1, 42); // 使用类型less<T>的默认初始化对象compare(1, 42, comparelsbn);// ***********************************************************// 类模板默认实参。// ***********************************************************template<class T = int>class Numbers{......}Numbers<long double> lots_of_precision;Numbers<> average_precision; // 空<>表示我们希望使用默认类型,也就是int
