推进网站建设,wordpress 文章列表样式,怎么制作自己的商城,wordpress页面排版插件目录
非类型模板参数
模板的特化
概念
函数模板特化
类模板特化
全特化
偏特化
模板的分离编译
分离编译的概念
模板的分离编译
编辑
模板总结 非类型模板参数
模板参数分为类型形参与非类型形参。
类型形参#xff1a;在模板参数列表中#xff0c;跟在class…
目录
非类型模板参数
模板的特化
概念
函数模板特化
类模板特化
全特化
偏特化
模板的分离编译
分离编译的概念
模板的分离编译
编辑
模板总结 非类型模板参数
模板参数分为类型形参与非类型形参。
类型形参在模板参数列表中跟在class或者typename之类的参数类型名称。
templateclass T
void swap(T x, T y)
{T tmp x;x y;y tmp;
}
非类型形参就是用一个常量作为类函数模板的一个参数在类函数模板中可将该参数当成常量使用。
templateclass T, size_t N 30
class A
{
private:T _array[N];
};int main()
{Aint a1; // N 30Aint, 10 a2; // N 10;return 0;
}
注意
1.非类型模板参数给的常量的缺省值只能是整型常量不能是浮点数、类对象和字符串等。 2.非类型模板参数必须在编译期就能确认结果。
以下用法是错误的因为N不确定。 模板的特化
概念
通常情况下模板可以实现一些与类型无关的代码但对于一些特殊类型比如指针可能会得到一些错误的结果。
就比如说一个小于的比较函数模板。
templateclass T
bool Less(T x, T y)
{return x y;
}
对于普通的int、double等类型这个函数可以得到正确结果。
cout boolalpha Less(3, 4) endl;
cout boolalpha Less(1.0, 5.0) endl; 但如果对于指针类型那结果就有问题了。
int a 8;
int b 4;
cout boolalpha Less(a, b) endl; 很明显这个结果是错的正确结果应该是false因为这个Less函数比较的是a、b的地址没有比较指针指向的内容。
为了解决这种问题就引入了模板特化了。
模板特化在原模板的基础上针对特殊类型进行特殊化的实现方式。
模板特化分为函数模板特化与类模板特化。
函数模板特化
函数模板特化的条件
1.一个基础的函数模板。
2.关键字template后面接空。
3.函数名后跟里指定特化的类型。
4.函数形参表必须要和模板函数的基础类型参数完全相同不同的话编译器会报错。
templateclass T
bool Less(T x, T y)
{return x y;
}//对Less函数模板进行特化
template
bool Lessint*(int* pa, int* pb)
{return *pa *pb;
}
进行特化后上面的例子就得到了正确答案了。
int a 8;
int b 4;
cout boolalpha Less(a, b) endl; 但是一般情况下函数模板遇到不能处理或者处理有误的类型时直接将该类型的函数给出。
bool Less(int* pa, int* pb)
{return *pa *pb;
}
这种实现简单明了代码可读性高而对于一些参数类型复杂的函数模板特化时比较麻烦因此函数模板不建议特化。
类模板特化
类模板特化也分全特化和偏特化。
全特化
全特化就是将模板参数列表所有参数都确定化。
templateclass T1, class T2
class Data
{
public:Data(){cout DataT1, T2 endl;}
private:T1 _x;T2 _y;
};template
class Dataint, char
{
public:Data(){cout Dataint, char endl;}
private:int _x;char _y;
};
全特化就是将T1和T2确定为int和char。
//匹配原始类模板
Dataint, double D1;//匹配特化的类模板
Dataint, char D2; 偏特化
有两种表现表现方式
部分特化将模板参数列表中的一部分参数特化。
templateclass T1, class T2
class Data
{
public:Data(){cout DataT1, T2 endl;}
private:T1 _x;T2 _y;
};templateclass T1
class DataT1, int
{
public:Data(){coutv DataT1, int endl;}
private:T1 _x;int _y;
};
将第二个参数T2特化成int只要第二个参数类型是int就匹配特化版本。
//匹配原始类模板
Dataint, double D1;
Datadouble,char D2;
cout endl;//匹配部分特化的类模板
Dataint, int D3;
Datachar*, int D4;
Datadouble, int D5; 参数限制针对模板参数更进一步的条件限制设计出来的一个特化版。
templateclass T
class Less
{
public:bool operator()(const T x, const T y){return x y;}
};//偏特化对参数类型做出进一步的限制
templateclass T
class LessT*
{
public:bool operator()(const T* pa, const T* pb){return *pa *pb;}
};
这里进行了一个偏特化将模板参数T限制为T*这样在传入指针类型时就会匹配偏特化版本对指针指向的内容进行比较而不是存储的地址。
运行例子
int a 3;
int b 10;cout boolalpha Lessint()(a, b) endl;//匹配偏特化
cout boolalpha Lessint*()(a, b) endl; 模板的分离编译
分离编译的概念 一个程序项目由若干个源文件共同实现而每个源文件单独编译生成目标文件最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。 模板的分离编译
对于一般的分离编译我们可以将函数的声明和定义分离但是对于模板我们将函数的声明和定义分离会导致链接错误。
原因如下 func.h 函数声明
func.cpp 函数定义
test.cpp 调用函数
报链接错误的直接原因就是链接时符号表没有对应函数的地址。
1.代码开始编译的时候首先就预处理把头文件展开、宏替换、条件编译、去掉注释.h和对应对的.cpp文件合在一起生成.i文件
2.然后就到编译根据语法树检查语法生成对应对的汇编代码模板这时候问题就出在这函数的.i文件有声明有定义没有具体类型test.i中有函数的声明有类型但是没有定义所以就不能生成具体的函数符号表也就没有对应的地址函数.i文件普通函数有声明有定义有类型可以生成这时test.i还是转换成汇编 call func(?),等着链接时把地址连接上也没有报错由.i文件生成.s文件
3.编译完就到了汇编汇编代码转换成二进制机械码生成.obj文件
4.链接时把目标文件合并在一起生成可执行程序并把需要的函数地址等连接上。
解决方法声明和定义不分离推荐模板定义的位置显式实例化。
模板总结
模板的优点
1.代码可以复用节省资源提高效率便于更快迭代开发C标准模板STL因此而生。
2.代码更灵活。
模板的缺点
1.代码膨胀编译时间变长。
2.模板出现错误时信息容易错乱不利于排查。 拜拜下期再见
摸鱼ing✨