模板的进阶
非类模板参数
类模板的特化
静态数组:array:template < class T, size_t N > class array; array为可以存放N个元素的数组模拟实现:
#include<iostream>
using namespace std;
namespace bit{
template < class T, size_t N > ;
class array{
public:
private:
//T类型参数,N非类型参数
T array[N];
};
}
int main(){
bit::array<int,10> a;
return 0;
}
模板---->任意类型都可以处理
特化---->对模板不能处理或者处理有误的类型进行特殊化处理(比如对于char *类型,是一个字符串,比较时应该通过字符串的方法进行比较,但是通过这个模板进行比较时直接用大于小于><进行比较,所以需要对模板进行特化)
1.必须提供一个类模板(对于函数模板,一般不进行特化)
template<class T>
T& Max(T& a,T& b){
return a>b?a:b;
}
template<>
char *& Max<char *>(char *& left,char *& right){
//不能加const,否则会出错,报错:不是函数模板的专用化
//加了之后对于特化的成本增加了
//如果处理不了,直接给出这种处理的函数即可,不需要特化
if(strcmp(left,right)>0){
return left;
}
retrun right;
}
int main(){
int a=0;
int b=3;
cout<<Max(a,b)<<endl;
char *p1="hello";
char *p2="world";
cout<<Max(p1,p2)<<endl;
return 0;
}
类模板的特化:
1.全特化:类模板实例化期间将类型全给出来比如:class Data<int , double>
2.偏特化(1)部分特化:class Data<int ,T>
(2) 让模板的参数列表中的类型参数限制更加严格class Data<T*,T*>
应用场景:识别被拷贝的元素的类型是内置类型还是用户自定义类型?
内置类型:不会涉及资源的管理
自定义类型:会涉及类型的管理
类型萃取:
//实现通用的拷贝函数:
template<>
//内置类型
struct TypeTraits<char>{
typedef TrueType POD_TYPE;
};
template<>
struct TypeTraits<double>{
typedef TrueType POD_TYPE;
};
struct TypeTraits<int>{
typedef TrueType POD_TYPE;
};
template<>
struct TypeTraits<float>{
typedef TrueType POD_TYPE;
};
//是实现的通用的类型,进而判断是内置类型还是自定义类型
template<>
struct TypeTraits<T>{
typedef FalseType POD_TYPE;
};
struct TrueType{
static bool Get(){
return true;
}
};//代表内置类型
struct FalseType{
static bool Get(){
return false;
}
};//代表自定义类型
template<class T>
void Copy(T* dst,T* src,size_t size){
if(TypeTraits<T>::POD_TYPE::Get()){
memset(dst,src,sizeof(T)*size);
}
else{
for(i=0;i<size;++i){
dst[i]=src[i];
}
}
模板的分离编译:
预处理阶段---->编译---->汇编---->链接---->可执行程序
1.预处理 宏替换,宏展开,删除注释,包含头文件
2.编译:语法分析(语法树—>中序遍历),语义分析,词法分析(扫描),代码优化;编译器只编译当前工程的所有源文件,头文件不参与编译(?????),头文件已经展开了。对于当前工程的所有源文件,分别单独编译,分别生成目标文件
1.对模板进行简单的语法检测
2.生成代码-->前提(实例化)
未解决的符号表
编译期间生成未解决的符号表,链接期间进行解决(链接期间到别的已解决的符号表中去找,如果没找到则报错:无法解析的外部符号;如果找到了,则解决了该问题(地址问题))
已解决的符号表
模板的分离编译:
解决这种问题通过建立全新的"头文件"“.hpp”,相当于将头文件和源文件合并到一块了
推荐方法:
//a.hpp
template<class T,class T>
T& Add(T& left, T& right){
return left+right;
}
//.cpp
#include"a.hpp"
int main(){
Add(1,2);
Add(1.0,3.0);
return 0;
}
另一种方法(不推荐)
a.cpp:
T& Add(T& left,T& right){
return left+right;
}
void testFun(){
这种方法是通过下面代码进行模板的实例化,生成相应的函数,如果不给出实例化,由于每个源文件是单独编译的,因此对于test.cpp源文件中的Add(1,2)会生成未决符号表,在链接期间没有找到相应的函数,所以会报错:无法识别的外部符号
Add(2,1);
Add(2.0,1.0);
}
a.h
template<class T,class T>
T& Add(T& left,T& right);
test.cpp:
#include"a.h"
int main(){
Add(2,1);
Add(2.0,1.0);
return 0;
}