模板参数分两种:
- 类型参数(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();
else
return 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