cpp学习-第十六章-模板与泛型编程

核心简记

模板是创建类或函数的公式,为编译时使用。
模板应该尽力减少对实参类型的要求。
使用模板时才会生成代码,定义模板并不会。因此为了编译模块找到定义,必须把模板类/函数定义、声明等都放在头文件供使用。
c++为了一遍编译语法大量多余.比如区分T的静态对象与类型对象、返回值在作用域外之类,都是为了编译时可以一遍编译而设置的。

定义模板

函数模板

1
2
3
4
5
6
template<typename T>
inline //inline与constexpr放这里
int f(T a,T b)
{
....
}

模板定义使用关键字template开始,<>内为模板参数列表,不能为空。使用模板时隐式或显示将模板实参绑定模板参数上。
对于函数可以自动推断,或显示使用:

1
2
f(1,3);
f<int>(1,3);

类型参数在函数体内任意使用。声明为类型时class或typename都可以当关键字。类型还可以是一个值:

1
2
template<unsigned N>
...

实例化时必须传入常量表达式,值的类型可以是整形、指针、左值引用。

类模板

编译器不能为类模板自动推断类型,必须手动使用<>
定义方式:

1
2
3
4
5
6
7
template <typename T>
class A{
在类模板的作用域下,使用A而不必使用A<T>
}
使用:
A<int> a;

每个实例生成独立的类,与其它同一模板生成的无关。
定义在类模板内的函数隐式inline,外的定义方式:

1
2
template<typename T>
A<T> A<T>::f(T ls){} //遇到类名才进入类的作用域,因此使用A<T>

在A中定义了f函数。
一个类模板的成员函数只有使用时才实例化,这使得传入类型不必完全符合模板操作要求。

杂记

友元与模板各自是否是模板是无关的。
根据声明方式可以模板类型一对一、一对多、多对一。
可以使用typedef A< int> AINT 简化一个实例,using则可更改模板名。
static成员绑定实例,使用时实例化.
T可以是任意名字,名字在编译时都作为符号表项,因此不同类型的名字作用域是互相影响的,模板参的名字也按名字查找与隐藏。
模板也可以声明
使用T的类型成员时前要加typename。否则会当成静态成员。
可以加默认模板实参:template < typename T=int> 使用时即使使用默认也要加<>
成员模板不能是虚函数,可以与类模板独立定义,独立处理类型。
可以使用显示实例化提前实例一个模板实例:

1
2
extern template 名字;//声明
template 名字;//定义

定义时实例化到模块、声明连接用。

模板的参数推断能转化的只有顶层、底层const、函数数组指针。
指定类型时可按一般的转化。

type_traits库中有类型转化的模板,如将引用、const去掉等。

多个模板函数与普通函数可选时:
选同好->选非模板->选作用范围更小的模板(更特例化)

可以使用…传多个模板参数与模板函数的参数。

模板可以特例化,即手动代替编译器的部分工作,函数模板特例化生成函数的实例。
类模板的特例化甚至可以只是部分特例化,生成范围更小的模板。如hash< type>的定义使用、之前type_traits库的转化。

反编译

为编译时任务,在反汇编时基本看不出差别。都是普通的对象生成与函数调用。