怎样做p2p网站,中小企业网站建设,中核二二公司是国企还是央企,锦州网站建设最低价目录
非类型模板参数
C11的静态数组容器-array
按需实例化
模板的特化
函数模板特化
类模板特化
全特化与偏特化
模板的分离编译
总结 非类型模板参数
基本概念#xff1a;模板参数类型分为类类型模板参数和非类类型模板参数
类类型模板参数#xff1a;跟在class…目录
非类型模板参数
C11的静态数组容器-array
按需实例化
模板的特化
函数模板特化
类模板特化
全特化与偏特化
模板的分离编译
总结 非类型模板参数
基本概念模板参数类型分为类类型模板参数和非类类型模板参数
类类型模板参数跟在class 或 typename之后的形参非类类类型模板参数用一个常量作为类模板的参数
功能编译时合理分配大小
#include iostream
using namespace std;namespace bit
{templateclass T, size_t N 10class array{public:T operator[](size_t index){return _array[index];}const T operator[](size_t index)const{return _array[index];}size_t size()const{return _size;}bool empty()const{return 0 _size;}private:T _array[N];size_t _size;};
}int main()
{bit::arrayint a1;bit::arrayint, 10 a2;bit::arrayint, 100 a3;return 0;
}
注意事项
1、浮点数、类类型的对象及字符串不允许作为非类类型模板参数
2、非类类型模板参数是在编译时传参函数参数是在运行时传参 3、函数参数T 对象1T 对象2| 模板参数class 类型1class 类型2
C11的静态数组容器-array array文档array - C Reference (cplusplus.com) #include iostream
#include assert.h
#include array
using namespace std;int main()
{std::arrayint, 10 a1;int a2[10];//越界读检查不出来a2[10];//越界写抽查局限多,很多位置查不出来x86环境下运行a2[15]不报错a[10] 1报错a2[15] 1;//任意读写越界都能检查出来a1[10];//报错return 0;
}优点 可以避免数组越界问题但实际上这些内容vector就可以做到array没啥用
std::vectorint v1(10,0);
v1[10]//v1[10]也可以检测出
缺点会出现栈溢出问题
std::arrayint,1000000 a3;//报错
std::vectorint v2(1000000,0);//正确
按需实例化
include iostream
#include array
#include vector
#include assert.h
using namespace std;namespace bit
{templateclass T, size_t N 10class array{public:T operator[](size_t index){assert(index N);size(1);//语法错误但是不报错return _array[index];}const T operator[](size_t index)const{assert(index N);return _array[index];}size_t size()const{return _size;}bool empty()const{return 0 _size;}private:T _array[N];size_t _size;};
}int main()
{bit::arrayint a1;couta1.empty()endl;//不报错a1[1];//增加一个调用a1[1]时报错return 0;
}
运行上述代码后不会报错即使size(1)是一个语法错误size函数不需要传参这是因为
在编译器遇到模板时预处理阶段后不会直接编译而是根据模板的“蓝图” 传入模板的参数类型等内容将模板进行实例化后才会进行编译阶段调试时是已经经历了四个阶段的在实例化类模板时会进行按需实例化即调用哪个成员函数就实例化哪个调用empty就仅实例化该函数
没有报错的本质就是没有调用operator[]所以operator[]中的错误不会被检查出来只有调用才会细致检查语法错误 当然编译器还是会大体框架进行检查比如少了}多个}之类的错误
模板的特化
基本概念在原模板类的基础上针对特殊类型所进行特殊化处理 通常情况下使用模板可以实现一些与类型无关的代码但对于一些特殊类型的可能会得到
一些错误的结果需要特殊处理比如实现了一个专门用来进行小于比较的函数模板
#include iostream
using namespace std;class Date
{
public:friend ostream operator(ostream _cout, const Date d);Date(int year 1900, int month 1, int day 1): _year(year), _month(month), _day(day){}bool operator(const Date d)const{return (_year d._year) ||(_year d._year _month d._month) ||(_year d._year _month d._month _day d._day);}bool operator(const Date d)const{return (_year d._year) ||(_year d._year _month d._month) ||(_year d._year _month d._month _day d._day);}
private:int _year;int _month;int _day;
};ostream operator(ostream _cout, const Date d)
{_cout d._year - d._month - d._day;return _cout;
}// 函数模板 -- 参数匹配
templateclass T
bool Less(T left, T right)
{return left right;
}int main()
{cout Less(1, 2) endl; // 可以比较结果正确Date d1(2022, 7, 7);Date d2(2022, 7, 6);cout Less(d1, d2) endl; // 可以比较结果正确会调用日期类对象的重载Date* p1 d1;Date* p2 d2;//传入日期类对象的指针进行比较cout Less(p1, p2) endl; // 可以比较结果错误return 0;
} p1指向的d1显然大于p2指向的d2对象但是Less内部并没有比较p1和p2指向的对象内容
而比较的是p1和p2指针的地址因而无法达到预期而错误
函数模板特化
注意事项
1、必须要现有一个基础的函数模板2、template后接一个空的尖括号3、函数名后跟一对尖括号尖括号中指定需要特化的类型4、函数形参顺序必须要和模板函数的基础参数类型完全相同若不同则编译器可能报错
#include iostream
using namespace std;class Date
{
public:friend ostream operator(ostream _cout, const Date d);Date(int year 1900, int month 1, int day 1): _year(year), _month(month), _day(day){}bool operator(const Date d)const{return (_year d._year) ||(_year d._year _month d._month) ||(_year d._year _month d._month _day d._day);}bool operator(const Date d)const{return (_year d._year) ||(_year d._year _month d._month) ||(_year d._year _month d._month _day d._day);}
private:int _year;int _month;int _day;
};ostream operator(ostream _cout, const Date d)
{_cout d._year - d._month - d._day;return _cout;
}//函数模板
templateclass T
bool Less(T left, T right)
{cout bool Less(T left, T right) endl;return left right;
}特化(但是该特化还是会出错)
//template
//bool Less(Date* left, Date* right)
//{
// cout bool Less(T* left, T* right) endl;
// return *left *right;
//}//不会出错但是不符合特化定义
templateclass T
bool Less(T* left, T* right)
{cout bool Less(T* left, T* right) endl;return *left *right;
}int main()
{cout Less(1, 2) endl; // 可以比较结果正确Date d1(2022, 7, 7);Date d2(2022, 7, 8);cout Less(d1, d2) endl; // 可以比较结果正确Date* p1 new Date(2022, 7, 7);Date* p2 new Date(2022, 7, 8);cout Less(p1, p2) endl; // 可以比较结果错误int* p3 new int(3);int* p4 new int(4);cout Less(p3, p4) endl; //可以比较结果错误return 0;
}~~依然是哪个类型更匹配就用哪个 ~~ 结论函数模板不建议特化do且函数模板特化的使用场景少
类模板特化
全特化与偏特化
全特化将模板参数列表中的所有参数都确定化
偏/半特化将模板参数列表中的部分参数确定化
偏特化又分为“部分特化” 和“参数更进一步的限制”
#include iostream
using namespace std;//Data类模板
templateclass T1,class T2
class Data
{
public:Data(){cout DataT1,T2 endl;}
private:T1 _d1;T2 _d2;
};//全特化
template
class Dataint,char
{
public:Data(){cout Dataint,char endl;}
};//偏/半特化(部分特化)
templateclass T1
class DataT1, char
{
public:Data(){cout Data T1,char endl;}
};//偏/半特化(对参数进一步限制)
templateclass T1,class T2
class DataT1*, T2*
{
public:Data(){cout Data T1*,T2* endl;}
};//偏/半特化(对参数进一步限制)
templateclass T1, class T2
class DataT1, T2*
{
public:Data(){cout Data T1,T2* endl;}
};int main()
{Dataint, int d1;Dataint, char d2;Datachar, char d3;Datachar*, char* d4;Dataint*, char* d5;Dataint*, string* d6;Dataint, string* d7;return 0;
} 匹配机制有现成的就用现成的没有现成的就用那个最合适的
注意事项如果传入的是Data*特化时的T*就会变成Date*而不是Data**T*是一个整体
模板的分离编译
基本概念一个程序/项目由若干个源文件共同实现而每个源文件单独编译生成目标文件最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式
假如有以下场景模板声明和定义分离在头文件中进行声明在源文件中进行定义
//a.h文件
tempateclass T
T Add(const T left,const T right);//a.cpp文件
templateclass T
T Add(const T left,const T right)
{return left right;
}//main.cpp
#include a.h
int main()
{Add(1,2);Add(1.0,2.0);return 0;
} 22、233处 注意事项模板的声明和定义支持分离但不支持分离在两个文件STL库中的模板的定义和分离都是在.h文件中的
总结
优点
复用了代码节省资源更快的迭代开发C的标准模板库也因此而生增强代码灵活性
缺点
模板会导致代码膨胀问题也会导致编译时间变长出现模板编译错误时错误信息十分混乱不易定位
~over~