1.非类型模板参数
模板参数分为类型形参与非类型形参类型形参(可以认为是虚拟类型):出现在模板参数列表中,跟在class或者typename之类的参数类型名称。非类型形参(可以认为是常量):用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。注:1.模板的非类型形参可以认为是常量,在模板中不能被修改2.浮点数、类对象以及字符串是不允许作为非类型模板参数的(非类型模板参数一般使用的都是整型,例如int、unsigned int、char)3.非类型的模板参数必须在编译期就能确认结果
容器array(c++11新增的容器)是一个固定大小的顺序容器,相当于定长数组。如下图所示,容器array类模板的官方库声明中,就有非类型模板参数N,N就是开辟array容器的元素个数。
array与vector相比:容器array的所有功能使用vector都可以实现。与vector有一点不同的是array里面存的就是全部的数据,数据全部存在栈里,而vector里面其实只有几个指针,vector里面的数据都存在堆里。实际中栈空间很小堆空间很大,所以vector更优。
array与原生数组相比:array其实就是封装过的原生数组,二者的区别是array对于越界的读写都可以检查出来(operator[ ]能严格检查越界),而原生数组是抽查不一定能检测出来。
总结:array对比原生数组还是有一些越界检查的优势的,但是实际中我们统一直接用vector更好。
如下图一所示代码定义一个静态栈,这样的代码有一个缺陷就是如果同时定义多个栈,这些栈的大小都是一样的。我们可以使用非类型模板参数来解决这个缺陷,灵活的控制每一个静态栈的大小。
2.模板的特化
2.1.概念
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,如下图所示第一二个结果是我们所想的,但是第三个和我们预期的结果不同,其实第三个结果值是随机的,第三个这里比较的是p1和p2指针指向地址的大小,这里应该给Less函数传的是*p1和*p2,才是我们预期的结果。但是如果一定要让你传p1和p2给Less函数,而且要实现预期的逻辑和结果,就需要用到模板的特化,即在原模板类的基础上,针对特殊类型所进行特殊化的实现方式。模板特化中分为函数模板特化与类模板特化。
2.2.函数模板特化
函数模板的特化步骤:1. 必须要先有一个基础的函数模板2. 关键字template后面接一对空的尖括号<>3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误注:其实我们也可以直接写一个现成的Less函数,这个Less函数只负责处理Date*这种类型的,这样也是可以的,如下图所示,这里Less函数模板、Less函数模板特化、Less函数是可以同时存在的,Less(p1,p2)调用的是现成的Less函数。总结:1.函数模板基本不用特化方式处理,直接写一个具体类型的函数更好2.虽然函数模板可以用上面的方式直接写一个现成的函数来处理,不需要进行特化,但是类模板不能去写一个类来处理,因为函数可以重载但是类不能重载。
2.3.类模板特化
2.3.1.全特化
全特化:将模板参数列表中所有的参数都确定化,如下图所示
注:上面的全特化版本的功能简单的说就是,只要Data模板第一个参数是int第二个参数是char就走我
2.3.2.偏特化
偏特化:任何针对模版参数进一步进行条件限制设计的特化版本。偏特化有两种表现方式:第一种:部分特化,将模板参数类表中的一部分参数特化,如下图所示。注:上面的这种偏特化版本的功能简单的说就是,只要Data模板第二个参数是char就走我第二种:参数更进一步的限制,偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本,如下图所示。
注:
1.上面的第二种偏特化版本写了指针和引用两个版本,指针版本的功能简单的说就是,只要Data模板第一个参数是指针第二个参数是指针就走我,引用版本的功能简单的说就是,只要Data模板第一个参数是引用第二个参数是引用就走我
2.上面的d9是int*和int类型,所有的特化都不匹配,因此走的是原本的Data模板