网站建设价值,中国工程网亿美,网页传奇大全,静态网站一、非类型模板参数
模板参数分为#xff1a;类型形参、非类型形参
类型形参#xff1a;class与typename都是参数类型
非类型形参#xff1a;用一个常量作为模板的一个参数#xff0c;一般是整型常量
#includeiostream
#includearray
using namespace …一、非类型模板参数
模板参数分为类型形参、非类型形参
类型形参class与typename都是参数类型
非类型形参用一个常量作为模板的一个参数一般是整型常量
#includeiostream
#includearray
using namespace std;//class T为类型模板参数用于适配各种类型
//size_ t N为非类型模板参数只能为整型常量
templateclass T,size_t N//下面的size_t N虽然没有加const但默认为常量
class Array
{
public:
private:T _a[N];
};templateclass T,size_t N10
//templateclass T,double N10//会报错类型非法
void func(const T a)
{N 20;//会报错必须为可操作得左值说明N非类型模板参数为常量
}int main()
{//非类型模板参数可以对不同得对象开辟不同大小的空间Arrayint,10 a1;Arraydouble,20 a2;int arr[15];arrayfloat, 15 a3;//C11中更新的容器对标C语言中的静态数组//不提供初始化但是有严格的越界检查读写全面检查}
1.浮点数、类对象以及字符串是不允许作为非类型模板参数的
2.非类型模板参数必须在编译器就能确认
二、模板特化
模板对于一些特殊类型可能会产生一些错误的结果
就比如下面实现的比较大小的代码对于Date类的特定对象可以实现对比功能但是如果使用特定对象的指针进行比较就会产生错误
因此需要使用模板进行特化也就是在原来模板的基础上对特殊类型进行特殊化处理
#includeiostream
using namespace std;class Date
{
public: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);}friend ostream operator(ostream _cout, const Date d){_cout d._year - d._month - d._day;return _cout;}private:int _year;int _month;int _day;
};templateclass T
bool Less(T left, T right)
{return left right;
}int main()
{cout Less(1, 5) endl;//1 可以比较结果正确Date d1(2023, 5, 10);Date d2(2023, 5, 1);cout Less(d1, d2) endl;//0 可以比较结果正确Date* p1 d1;Date* p2 d2;cout Less(p1, p2) endl;//1 可以比较结果错误return 0;
} 可以参数Less函数一般都可以进行正常比较但是以如上代码为例进行自定义对象的对比正常但是对于指向自定义类型对象的指针对比错误。因此需要特化 1.函数模板特化
函数模板的特化步骤
1. 必须要先有一个基础的函数模板
2. 关键字template后面接一对空的尖括号
3. 函数名后跟一对尖括号尖括号中指定需要特化的类型
4. 函数形参表: 必须要和模板函数的基础参数类型完全相同如果不同编译器可能会报一些奇怪的错误
函数模板特化使用较少因为可以直接给出特定的函数用于实现也就是函数重载
#includeiostream
using namespace std;class Date
{
public: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);}friend ostream operator(ostream _cout, const Date d){_cout d._year - d._month - d._day;return _cout;}private:int _year;int _month;int _day;
};templateclass T
bool Less(T left, T right)
{return left right;
}//函数模板特化--对某些类型进行特殊化处理
template
bool LessDate*(Date* left, Date* right)//全特化
{return *left *right;
}//实例化重载
bool Less(Date* left, Date* right)
{return *left *right;
}void test_1()
{cout Less endl;cout Less(1, 2) endl;Date d1(2023, 5, 10);Date d2(2023, 5, 5);cout Less(d1, d2) endl;Date* p1 d1;Date* p2 d2;cout Less(p1, p2) endl;//调用特化之后的版本不通过模板生成
}int main()
{test_1();return 0;
}
2.类模板特化
类模板特化分为全特化和偏特化
全特化即是将模板参数列表中所有的参数都确定化
偏特化对模板参数进行限制的特化版本
全特化可以理解为所有参数都锁定的特化偏特化可以理解为部分参数特化 #includeiostream
using namespace std;//类模板
templateclass T1,class T2
class modle
{
public:modle(){cout modleT1,T2 endl;}
private:T1 _m1;T2 _m2;
};//类模板全特化
template
class modleint,char
{
public:modle(){cout modleT1,T2 endl;}
private:int _m1;char _m2;
};//偏特化
templateclass T1
class modleT1, int//将模板参数列表的一部分参数特化将第二个参数转化为int
{
public:modle(){cout modleT1,int endl;}
private:T1 _m1;int _m2;
};//将两个参数偏特化为指针类型
templatetypename T1,typename T2
class modleT1*, T2*
{
public:modle(){cout modleT1*,T2* endl;}
private:T1 m1;T2 m2;
};//将两个参数偏特化为引用类型
templatetypename T1, typename T2
class modleT1, T2
{
public:modle(const T1 m1,const T2 m2):_m1(m1),_m2(m2){cout modleT1,T2 endl;}
private:const T1 _m1;const T2 _m2;
};void test_2()
{modleint, int m1;//偏特化的部分参数特化版本modleint,char m2;//全特化modleint*, int* m3;//偏特化的指针版本modleint, int m4(1, 5);//偏特化的引用版本
}int main()
{test_2();return 0;
}
三、模板的分离编译
一个项目由若干个源文件共同实现每个源文件会独立线性生成相应的预处理文件(.i)编译文件(.s)汇编文件(.o)最后再将所有目标文件链接形成单一的可执行文件的过程为分离编译模式 func.h
#pragma once
#includeiostream
#includearray
#include vector
using namespace std;templateclass T
T Add(const T left, const T right);templateclass T
T Add(const T left, const T right)
{return left right;
}// 声明和定义放到一起直接就可以实例化编译时就有地址不需要链接void func();
//模板不支持声明与定义不在同一个文件
//但是模板支持在一个文件内部声明和定义分离#includefunc.h
templateclass T
T Add(const T left, const T right)
{return left right;
}void func()
{cout void func() endl;
}//显式实例化此时编译时就知道需要实例化一个double类型的Add函数
template
double Adddouble(const double left, const double right);
//但是这样对于其他类型需要不断得显示实例化十分麻烦工程只有再链接的时候才会寻找函数地址但是函数模板只有在调用的时候才会产生实例化因此再没有实例化的时候并没有地址在链接时会产生报错
解决方法
1.将声明和定义放在同一个文件内一般都是统一放在头文件内
2.模板定义的位置显示实例化对于多个不同类型调用十分麻烦不建议使用
模板总结
优点缺点模板复用代码节省资源使得代码简明高效模板会导致代码膨胀对于不同的类型进行不同的实例化会导致编译时间变长增强的代码的灵活性出现模板编译错误时错误信息凌乱不易定位