模板,std::function

泛型&多态

  1. 泛型(Generics):与数据类型无关的代码,比如模板
  2. 多态:以相同的接口操作,比如函数重载

函数模板

  1. 定义:template <typename | class 关键字 + 模板参数名 ……模板参数列表>函数的定义,声明也需要模板实参列表
  2. 类型模板参数:用typename | class关键字指定,可以作为函数内任何可以使用类型的位置上
  3. 非类型模板参数:内置类型指定,表示值非类型,同样可以作为函数内任何可以使用类型的位置上
  4. 实例化函数模板:调用函数:我们可以显示指定模板实参 | 隐式:当调用函数模板时,会自动推断模板实参(对于非类型必须提供常量表达式类型实参)代替模板参数创建出新的模板实例
  5. inline 和 constexpr要放在模板参数列表后,返回类型前
  6. 模板定义,类定义,函数声明,变量声明,都不会生成代码,并且如果要实例化,编译器必须掌握模板的定义,所以,需要最好放在头文件中,可以被多个cpp文件使用

类模板

  1. 定义类模板:template <typename | class>  class……,声明也需要模板实参列表
  2. 实例化类模板:创建类对象:必须提供显示模板实参列表,不能自动隐式推断,通过类名后<type>类对象名,实例化特定类型的类模板
  3. 定义类模板的成员函数:定义在类外的必须以<template T>模板参数列表开始,类名后加<T模板参数列表>:类名<T>:: 函数()
  4. 实例化类模板的成员函数: 调用成员函数,才会实例化

类模板static成员:

  1. 每个模板T实例都有自己的static成员,所有的T类型模板类对象共享相同的static成员
  2. 通过::访问时必须在类名后加上<type>实参,否则无法确定是哪个模板实例的static成员
  3. ::可以访问类的static或类型成员,在非模板类中,编译器有类的定义,因此可以区分,但是对于模板类,只有实例化才知道
  4. 在默认情况下,c++会假定访问的是名字非类型,可以通过关键字typename显示告诉编译器它是类型

模板参数

  1. 在模板内不能定义/声明,和模板参数名相同的变量名
  2. 默认函数实参:通常不指定实参时使用默认值,指定时使用指定的值
  3. 默认函数模板实参:可以配合函数默认实参使用,否则没有意义
  4. 作为函数默认实参的类型,也就是当调用函数不传递最后的实参时,形参的类型是默认的默认模板实参类型,否则是传入的实参类型
  5. 默认类模板实参:类模板的对象必须显示实例化,当我们在类模板定义指定默认类型 T = type 时,实例化用空的<>表示使用默认的类模板实参

类模板和友元

  1. 不要忘记前向声明友元类 / 函数
  2. 对于class类和friend友元是否是模板,关乎到授权所有实例还是特定类型实例:
  3. 模板类的非模板友元:
    1. 非模板友元可以访问所有类型模板类实例
  4. 普通类的模板友元:
    1. 特定友元:friend class 类名 <type>;type类型的模板友元可以访问普通类
    2. 通用友元:template<typename T> friend class | struct 类名;所有类型的模板友元可以访问普通类
  5. 模板类的模板友元:
    1. 特定友元:friend class 类名<type>;类的每个实例,T类型的模板友元可以访问T类型的模板类实例
    2. 通用友元:template<typename X> friend class 类名;任何类型的模板友元可以访问任何类型的模板类实例

类模板类型别名

  1. typedef 不能直接为模板本身创建别名,仅可以为具体实例化创建别名
  2. typedef 类模板名<type> 别名;但不可以typedef 类模板名<T> 别名
  3. 而using可以为模板本身创建别名:template<typename T……> using 别名 = 类模板名<模板参数列表>

类成员模板

  • 成员模板:
  • 普通类的成员模板:
  • 类模板的成员模板:有各自的独立模板参数列表,当定义时需要同时提供类和函数的template,当实例化成员模板时,需要同时提供类和函数的实参

可调用类型

  1. std::function可以解决不同可调用对象,使用相同调用形式的情况
  2. 初始化:function <函数返回类型<形参类型列表>> f = 可调用对象;:表示f可以存储返回类型为…… ,形参列表的类型为……可调用对象的空function,并将为它赋予了初始值,一个可调用对象
  3. 使用:f(实参列表),表示为f的可调用对象传递实参

阅读方式

  1. 带括号的,由内而外,由指令的最右到左

控制实例化

  1. 每次使用模板,都会实例化特定的模板代码,很多情况不同cpp文件,实例化的版本都是重复的,
  2. 可以通过控制声明和定义,显示控制实例化的次数为1次
  3. 定义(仅一次)(最好在同一个特定文件中):template 类 | 函数 模板声明;
  4. 声明:extern template 类 | 函数 模板声明;接着当实例化类 | 函数时,便会使用模板的定义实例化的版本
  5. 对于这种实例化方式,类会实例化所有成员

模板实参推断 & 类型转换

  1. 由函数实参推断模板实参的过程,叫做模板实参推断,
  2. 类型转换:我们会将推断的模板实参,传递给函数形参,其中仅能做出有限的几种转换:
    1. 顶层const会被忽略,无论是实参还是形参
    2. 对于引用|指针的底层const,可以由非const模板实参,到const函数形参转换
    3. 当函数形参非引用类型,可以将数组实参转换为首元素指针,函数实参可以转换为函数指针,对于引用类型,不会发生此转换
  3. 如果上述过程失败,则调用失败
  4. 对于算数转换,派生到基类等转换都不能用于函数模板
  5. 特殊:如果函数形参是非模板类型,那么可以使用正常的类型转换
  6. 注意:同一模板形参类型,不能由不同函数实参推断

显示函数模板实参

  1. 在实例化时在函数名后<type模板实参列表>,列表和模板形参从左至右一一匹配
  2. 如果我们显示指定模板实参,对于此模板类型的函数形参,可以正常类型转换
  3. //
  4. 显示实参,可以使用尾置返回类型,和自动推断简化
  5. 函数模板可以初始化或赋值函数指针,这是会使用指针的类型为模板推断实参,但如果无法确定唯一的推断,二义性将发生错误

重载模板

  1. 函数匹配:
    1. 当模板实参推断成功,并且类型转换成功,为精准匹配
    2. 当多个可行匹配:
      1. 只有一个非模板,选择此函数
      2. 当没有非模板函数,选择最特例化(比如非const比const特例化)的版本
      3. 否则有歧义

可变参数模板

  1. 模板参数包:typename... 模板参数名,表示有0个或多个参数数目
  2. 函数参数包:模板参数名(作为类型)... ,
  3. 函数模板可以自动推断模板实参类型,而参数包可以自动推断模板实参的个数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值