模板进阶部分

一。非类型模板参数

定义:指不是类型的模板参数,C++20前只支持整形,之后支持内置类型

注意:1.这参数被用时被看作常量,不可修改,但能定义静态数组

2.不同参数模板生成的类不是同一类型(模板本质是根据不同参数生成不同类)

3.可以给缺省值(类的,非类型参数的都行)

(补充:用时实例化:类中的成员函数只有在被使用时才会实例化它(按需实例化),才会语法检查)

(模板尖括号位置不变,都是在名字后)

用法:静态栈指定大小初始化

一。二-非类型模板参数的实例

array(C++11增加)

定义:固定大小的静态数组,加了一些封装方法等

优势:数组越界严格检查(自定义类型符号重载 [ ] 函数内严格检查)

(补充:数组越界检查

C++数组越界检查编译器一般只检查邻近位置,如int a[10],使用只检查a[10]和a[11]的越界使用,而且只检查越界写,其他检查不出来。

为什么?数组越界检查每次使用检查成本高,所以设置标志位置 检查越界写,越界读不会报错,检查标志位置值有没有被修改。)

注意:其只负责开空间,不会对空间初始化

缺点:在栈上开空间,栈帧不大,一般只有8M,它太大可能栈溢出

使用:一般很少用,可以用vector在堆上开空间替代

补充:模板使用,模板参数为模板

打印vector

#include<iostream>
#include<vector>
using namespace std;
template<class T>
void PrintVector(const vector<T>& v)
{
	for (auto e : v)
	{
		cout << e<<" ";
	}
	cout << endl;
}
int main()
{
	vector<int> v1{ 1,2,3,4 };
	vector<double> v2{ 1.1,2.2,3.3,4.4 };
	PrintVector(v1);
	PrintVector(v2);
	return 0;
}

补充:必须使用typename的

#include<iostream>
#include<vector>
using namespace std;
template<class T>
void PrintVector(const vector<T>& v)
{
	//vector<T>::const_iterator it = v.begin();\
	错误:编译器语法检查从上往下检查,但只检查实例化了的模板类,不然只检查模板的‘壳’,\
            比如模板定义语法,分号尖括号等\
          这里没有实例化,但又用了模板里面的内容,\
		  编译器不会再去找(成本高,数量多),\
          但不知道这指定的是类里的类型还是静态成员,\
        所以要程序猿加个typename告知这是类型
	//总结:要调 未实例化的模板类 里的类型要加typename
	typename vector<T>::const_iterator it = v.begin();
//也可以直接用auto做类型避开
	while (it != v.end())
	{
		cout << *it++ << " ";
	}
	cout << endl;
}
int main()
{
	vector<int> v1{ 1,2,3,4 };
	vector<double> v2{ 1.1,2.2,3.3,4.4 };
	PrintVector(v1);
	PrintVector(v2);
	return 0;
}

二。模板特化

定义:针对特殊类型进行特殊处理

模板匹配时检测如果是特别类型,使用所特化的模板创建

模板直接也会重载

二。一  全特化

坑:

const本身与const指针

#include<iostream>
#include<vector>
using namespace std;
template<class T>
bool LESS(const T& t1, const T& t2)
{
	return t1 > t2;
}
template<>
bool LESS(int* const& t1, int* const& t2)
{
	return *t1 > *t2;
}
int main()
{
	int a = 1;
	int b = 2;
	cout << LESS(&a, &b) << endl;
	return 0;
}

模板比较参数时只要在T前const修饰本身,但特化时,对参数为指针的特化需要在int*后加const修饰本身,引用符号一定在最后,名字前。

建议:

不要用函数模板全特化,直接写对应函数,和模板生成的可以构成重载,会匹配更匹配的。

注意:类模板的特化很有必要,因为类没有重载的概念,对于模板的特殊类型只能特化写

二。二 偏特化(半特化)

1.

一个是模板参数,另一个是指定的参数

#include<typeinfo>
using namespace std;
template<class T,class B>
bool LESS(const T& t1, const B& t2)
{
	return t1 > t2;
}
template<class T>
bool LESS( T& t1, int* const& t2)
{
	return *t1 > *t2;
}
int main()
{
	int a = 1;
	int b = 2;
	//cout << typeid(&b).name() << endl;//&b类型为int*因为临时变量常性只对引用和运算起效
	int* const p = &b;
	cout << LESS(&a, p) << endl;
	return 0;
}

2.

指定类型大类:

应用:传指针比较

#include<iostream>
#include<vector>
#include<typeinfo>
using namespace std;
template<class T,class B>
bool LESS(const T& t1,  const B & t2)
{
	return t1 > t2;
}
template<class T,class B>
bool LESS( T* const & t1, B* const & t2)
{
	return *t1 > *t2;
}
int main()
{
	int a = 1;
	int b = 2;
	cout << LESS(&a, &b) << endl;
	return 0;
}

三。模板分离多文件问题

多个cpp文件包定义会冲突->要.h

模板项目可以是.h或.hpp既是.h也是.cpp

为什么包.h就能用函数->调用函数就是去找这个函数第一句指令的地址,链接时去找,

模板定义声明分离多个文件找不到->但是函数模板没有地址,不会被编译生成指令,没有对应模板生成的函数进符号表。

->调用的地方知道实例化成什么,但只有函数/类声明没有模板定义,模板定义的地方不知道实例化成什么

解决:显式实例化,在对应模板定义文件内实例化一个对应的。

template
int Add(const int& left,const int& right)

编译器在链接前多文件不会交互,为了编译速度,不然去单独找模板,速度极慢。

不分离到两个文件

同一文件内模板可以被找到,可以实例化成对应的函数/类。->包了.h就有模板定义就能实例化

所以:一个完整的模板都只放一个文件内,类模板成员函数短的放类里,内联,长的放类外,好看。函数模板直接定义。

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值