C++模板-进阶
目录
非类型模板参数
模板参数分 类型形参 和 非类型形参
类型形参:出现模板参数列表中,跟在class或者typename之类的参数类型名称
非类型形参:用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当常量来使用
namespace A
{
template<class T,size_t N = 10>
class arr
{
public:
T& operator[](size_t n) { return _arr[n]; }
size_t size() const { return _size; }
bool empty() const { return 0 == _size; }
private:
T _arr[N];
size_t _size;
};
}
其中N就是非类型形参
浮点数,类对象,字符串不可以当非类型模板参数
非类型的模板参数必须在编译期就能确认结果
模板的特化
通常情况下,使用模板可以实现一些与类型无关的代码,但是对于特殊类型也需要特殊处理
class Num
{
public:
Num(int a):_a(a){}
bool operator<(Num& b) { return _a < b._a; }
private:
int _a;
};
template<class T>
bool Less(T left, T right)
{
return left < right;
}
int main()
{
cout << Less(1, 2) << endl;//正确
Num n1(1);
Num n2(2);
cout << Less(n2, n1) << endl;//正确
Num* p2 = &n1;
Num* p1 = &n2;
cout << Less(p2, p1) << endl;//这里比的是地址 不是我们要的
return 0;
}
为了在对比指针时,转换为我们想要的对比方式,就需要对模板进行特化,就是在原模版类的基础上,针对特殊类型模板进行特殊化的实现方式,模板特化分为函数模板特化与类模板特化
函数模板特化
- 拥有原函数模板
- 用template<>进行特化
- 函数名字后也要有<>并且内部是特化类型
- 函数类型表:必须要和模板函数的基础参数类型相同
template<class T>
bool Less(T left, T right)
{
return left < right;
}
template<>
bool Less<Num*>(Num* left, Num* right)
{
return *left < *right;
}
类模板特化
全特化
全特化就是将模板参数列表中的所有参数都确定化
template<class T1,class T2>
class Num
{
public:
Num(T1 a1,T2 a2):_a1(a1),_a2(a2){}
private:
T1 _a1;
T2 _a2;
};
template<>
class Num<int,char>
{
public:
Num(int a1, char a2) :_a1(a1), _a2(a2) {}
private:
int _a1;
char _a2;
};
偏特化
不完全的特化类型
template<class T1,class T2>
class Num
{
public:
Num(T1 a1,T2 a2):_a1(a1),_a2(a2){}
private:
T1 _a1;
T2 _a2;
};
template<class T1>
class Num<T1, int>
{
public:
Num(T1 a1, int a2) :_a1(a1), _a2(a2) {}
private:
T1 _a1;
int _a2;
};
特殊偏特化
template<class T1, class T2>
class Num<T1*,T2*>
{
public:
Num(T1* a1, T2* a2) :_a1(a1), _a2(a2) {}
private:
T1* _a1;
T2* _a2;
};
template<class T1, class T2>
class Num<T1&,T2&>
{
public:
Num(T1& a1, T2& a2) :_a1(a1), _a2(a2) {}
private:
T1& _a1;
T2& _a2;
};
模板的分离编译
把多个源文件实现,单独编译,然后链接成单一可执行文件的过程叫做分离编译模式
在C++中,模板是一种允许程序员编写通用代码的工具,可以适应不同的数据类型和场景。然而,模板本身并不生成代码,只有当模板被实例化时,编译器才会根据模板定义生成相应的代码。这意味着,模板的实例化是在编译时进行的,而不是在链接时。
模板定义不可见:当模板的声明与定义分离,并且定义在另一个文件中时,编译器在实例化模板时可能找不到对应的模板定义。由于模板的实例化是在编译时进行的,如果编译器在实例化模板时无法访问到模板的完整定义,那么它将无法生成正确的代码,从而导致编译或链接错误。
符号表问题:符号表记录了程序中所有符号(如函数名、变量名等)的信息。对于模板来说,如果模板在某个源文件中被实例化,那么实例化后的函数或对象将会出现在该源文件的符号表中。但是,如果模板的声明与定义分离,且定义在另一个文件中,而这个文件在链接前没有被正确编译或包含,那么实例化后的符号可能就不会出现在最终的符号表中,从而导致链接错误。
解决方式
1.把声明和定义放到同一个文件里
2.模板定义的位置显式实例化
实例化:
// MyClass.cpp
#include "MyClass.h"
// 显式实例化 MyClass<int> 和 MyClass<double>
template class MyClass<int>;
template class MyClass<double>;
模板的总结
优点
- 代码重用:模板允许创建参数化的代码,从而大大减少重复代码,提高开发效率。
- 类型安全:模板提供编译时类型检查,确保类型正确,减少运行时错误。
- 性能优化:模板实例化是在编译时进行的,编译器可以针对特定的数据类型生成高效的代码。
缺点
- 编译时间增加:由于模板在编译时需要实例化多个版本,因此可能会增加编译时间。
- 代码膨胀:模板在编译时生成大量代码,可能会导致可执行文件体积增大。
- 易读性和调试困难:模板代码可能较为复杂,不易阅读和理解,同时在调试时也可能更加困难。
- 二进制兼容性问题:由于模板实例化是在编译时进行的,因此不同编译器或不同编译选项下生成的二进制代码可能不兼容。
- 限制:模板的某些高级特性(如局部特殊化和特殊化顺序)在不同C++标准实现中可能不统一,限制了模板的跨平台性和可移植性。
原文地址:https://blog.csdn.net/forccct/article/details/145246542
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!