3.模版与泛型知识点汇总

零.概览

  1. 函数模版

    • 类型模版参数(编译器可推断

    • 非类型模版参数

  2. 类模版

    • 类型模版参数(编译器不可推断

    • 非类型模版参数(浮点类型和雷类型不能做非类型模版参数

  3. typename适用场合

    • 函数模版和类模版中使用typename

    • 标明类型(标明一个在类模版的类中使用模版定义的类型,例如T*

    • 函数指针作为函数参数

      • 普通函数指针

      • 函数模版作为函数指针

      • 可调用对象作为函数指针

    • 默认模版参数

      • 类模版默认参数

      • 函数模版默认参数(注意写法

    • 成员函数模版

      • 普通类的成员函数模版

      • 模板类的成员函数模版(注意类内定义和类外定义区别

    • 防止出现多次实例化

  4. using定义模版别名和显式指定模版参数

    • using定义普通类型别名

    • using定义模版类型别名

    • using和typedef写法区别

    • 显示指定模版参数

  5. 模版特化(模版有特化版本必须有泛化版本,函数模版只有全特化没有偏特化

    • 模版全特化

      • 模版泛化

      • 模版全特化

    • 模版偏特化

      • 模版泛化

      • 模版偏特化(数量上偏特化,类型上偏特化

    • 重载函数和函数模版

      • 对于参数相同的函数模版和重载函数会优先调用:普通函数>特化版本>泛化版本

  6. 可变模版参数和模版模版参数

    1. 可变函数模版:一般函数+终止函数

    2. 可变类模版:泛化版本+特化版本+无参特化版本

    3. 可变类模版:递归形式和组合形式

    4. 案例:不同形式的递归展开tuple包

    5. 模版模版参数的两种写法:主要用作容器作为模版参数

一.函数模版

1.类型模版参数

(1)定义

(2)使用:编译器可推断类型

 2.非类型模版参数

(1)定义

(2)使用

(3)例子

 

二.类模版

1.类型模版参数:编译器不可推断参数类型

(1)定义

(2)使用

(3)模板类中成员函数类内声明类外定义写法

2.非类型模版参数

(1)定义

(2)使用

(3)注意事项

三.typename使用场合

1.模版中定义:函数模版和类模版

2.标明类型:标明是一种类型

  • 不标明会将域运算之后的认为成一个静态成员变量

  • 标明myiterator是一个类型

(1)例一:

 

 (2)例二:

  • 标明size_type类型是T类型中定义的类型

 3.函数指针作为其他函数参数在模版中使用

(1)一般函数指针写法

(2)函数模版中使用函数指针

(3)可调用对象充当函数

  • 传入重载圆括号运算符的函数对象,类似于传递函数指针

 

4.默认模版参数

(1)类模版默认参数

(2)函数模版默认参数

【1】普通值类型前面已经写过

【2】类类型作为默认参数

  • 同时需要将类名(F = tc)和临时对象(F funcpoint = F())

【3】函数指针作为默认类型

  • 同时需要函数指针(F = FunType)和函数名(F funcpoint = mf)

5.成员函数模版

(1)普通类的成员函数模版

(2)类模版的成员函数

【1】类内定义

【2】类外定义

6.防止出现多次实例化

  • 在某个.cpp中使用template定义

  • 在其他.cpp中使用extern声明已经由此实例了

(1)类模版防止多次实例化

 

(2)函数模版防止多次实例化

四.using定义模版别名与显式指定模版参数

1.using定义模版别名

(1)定义普通类型别名

(2) 定义模版类型别名

【1】使用typedef

【2】使用using:(推荐)

2.using与typedef对比

(1)普通类型

(2)模板类型

【1】函数指针模版

【2】类模版

3.显示指定模版参数

(1)定义模版函数

(2)使用:

  • 模版参数<int>为T1

  • T2,T3是自动推倒为int,int

  • 此处推导为int导致溢出,即使T1改为double也会溢出,值不正确

(3)正确使用

(4)注意

  • 不可省略前面的模版参数直接写后面的模版参数

五.模版特化

  • 模版有特化版本必须得有泛化版本

  • 函数模版只有全特化没有偏特化

1.模版全特化

(1)泛化版本

(2)类模版全特化

(3)函数模版全特化

2.类模版偏特化

(1)类模版泛化版本

(2)类模版参数数量上偏特化

(3)类模版类型上偏特化

3.重载函数和函数模版

(1)泛化版本

(2)全特化版本函数模版

(3)函数重载

 (4)注意事项

  • 对于上例中同样的普通函数和特化版本会先调用普通函数

六.可变参模板与模版模版参数

1.可变参数模版

1.1.可变参函数模版

(1)例子

(2)递归形式的可变参函数模版

  • 必须定义一般函数和终止函数

2.可变参类模版

(1)递归形式可变参类模版

  • 必须定义泛化+偏特化

  • 可选择定义无参的特化

【1】泛化版本

【2】偏特化版本

【3】无参的特化版本

【4】使用

【5】注意

  • 变参类模版,递归产生的父类模版与子类模版都是一样的

(2)组合形式的可变参类模版

  •  与递归形式相似,也需要泛化版本+特化版本+可省略的无参版本

  • 与递归形式相比只需要修改特化版本

【1】特化版本

【2】使用

(3)案例:使用递归调用展开tuple参数包

【1】类模版泛化版本

【2】递归调用类模版偏特化版本

【3】使用

  • 定义一个计数从0开始的模版

  • 最终会调用计数为最后一个数的偏特化版本的模版

 

3.模版模版参数

  • 模版中的参数是另一个模版类

  • 主要作用:让容器作为模版参数传入到模版中

(1)两种写法

【1】class类型写法:推荐写法

【2】typename类型写法:多了一个参数W,不推荐写

(2)例子:

【1】修改上图中的class 中内容

【2】使用using定义模板类别名

  • 由于vector等STL容器需要传入内存分配器所以使用using定义模板类别名

  • 由于涉及到模版模版参数传递导致默认分配器失效需要指定才这么写

【3】使用

七.总结完毕!

posted @ 2020-12-03 00:10  All_just_for_fun  阅读(116)  评论(0)    收藏  举报