模板参数分两种:

  • 类型参数(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 int compare(const T& v1, const T& v2){ if(v1 < v2) return -1; if(v2 < v1) return 1; return 0; }

  1. ```cpp
  2. // T: 类型参数,一般也叫模板类型参数
  3. // N, M:非类型模板参数,
  4. template<typename T, unsigned N, unsigned M>
  5. int compare(const T (&arr1)[N], const T (&arr2)[M]){
  6. ......
  7. }
  8. compare("hi", "mom");
  9. // 编译器在编译阶段推断出模板参数如下:
  10. // T: char
  11. // N: 3
  12. // M: 4
  13. // 正确,inline、constexpr说明符跟在模板参数列表之后
  14. template<typename T>
  15. inline T min(const T&, const T&);
  16. // 错误,inline说明符的位置不正确
  17. inline template <typename T> T min(const T&, const T&);

作用域

遵循普通的作用域规则。如果名字冲突,则隐藏外层作用域中的相同名字。

  1. typedef double T;
  2. // 正常的名字隐藏规则决定了上面的T被隐藏。
  3. template<typename T> // 模板参数名字T可以随便取但不能重复
  4. void calc(const T& a, const T& b){
  5. T c; // T是模板参数,而非double
  6. }

访问T的成员

访问模板类型参数 T 的成员。

  1. template<typename T>
  2. void fuck(const T& ){
  3. T::size_type *p;
  4. // 有两种语义。
  5. // 语义一:静态成员size_type 乘以 p
  6. // 语义二:声明定义size_type类型指针。
  7. }

如何让编译器认为我们是采用语义二的意思?在访问成员前面显式加上typename关键字,不能是class。

  1. // 以下模板函数返回T的尾元素,若为空,则创建一个T存储的元素类型的元素。
  2. template <typename T>
  3. typename T::value_type top(const T& c){
  4. if (!c.empty())
  5. return c.back();
  6. else
  7. return typename T::value_type();
  8. }

默认实参

模板参数列表也可以有默认实参,和函数默认实参一样,右侧参数必须都有默认实参。

  1. // ***********************************************************
  2. // 模板函数默认实参。
  3. // ***********************************************************
  4. template <typename T , typename F = less<T>>
  5. int compare(const T &v1, const T &v2, F f = F()){
  6. if (f(v1, v2)) return -1;
  7. if (f(v2, v1)) return 1 ;
  8. return 0;
  9. }
  10. compare(1, 42); // 使用类型less<T>的默认初始化对象
  11. compare(1, 42, comparelsbn);
  12. // ***********************************************************
  13. // 类模板默认实参。
  14. // ***********************************************************
  15. template<class T = int>
  16. class Numbers{
  17. ......
  18. }
  19. Numbers<long double> lots_of_precision;
  20. Numbers<> average_precision; // 空<>表示我们希望使用默认类型,也就是int