前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >C++模板-进阶

C++模板-进阶

作者头像
发布2025-01-20 17:21:08
发布2025-01-20 17:21:08
2900
代码可运行
举报
文章被收录于专栏:转自CSDN转自CSDN
运行总次数:0
代码可运行

非类型模板参数

模板参数分 类型形参 和 非类型形参

类型形参:出现模板参数列表中,跟在class或者typename之类的参数类型名称 非类型形参:用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当常量来使用

代码语言:javascript
代码运行次数:0
复制
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就是非类型形参 浮点数,类对象,字符串不可以当非类型模板参数 非类型的模板参数必须在编译期就能确认结果

模板的特化

通常情况下,使用模板可以实现一些与类型无关的代码,但是对于特殊类型也需要特殊处理

代码语言:javascript
代码运行次数:0
复制
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;
}

为了在对比指针时,转换为我们想要的对比方式,就需要对模板进行特化,就是在原模版类的基础上,针对特殊类型模板进行特殊化的实现方式,模板特化分为函数模板特化与类模板特化

函数模板特化

  1. 拥有原函数模板
  2. 用template<>进行特化
  3. 函数名字后也要有<>并且内部是特化类型
  4. 函数类型表:必须要和模板函数的基础参数类型相同
代码语言:javascript
代码运行次数:0
复制
template<class T>
bool Less(T left, T right)
{
	return left < right;
}
template<>
bool Less<Num*>(Num* left, Num* right)
{
	return *left < *right;
}

类模板特化

全特化

全特化就是将模板参数列表中的所有参数都确定化

代码语言:javascript
代码运行次数:0
复制
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;
};
偏特化

不完全的特化类型

代码语言:javascript
代码运行次数:0
复制
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;
};

特殊偏特化

代码语言:javascript
代码运行次数:0
复制
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.模板定义的位置显式实例化

实例化:

代码语言:javascript
代码运行次数:0
复制
// MyClass.cpp
#include "MyClass.h"

// 显式实例化 MyClass<int> 和 MyClass<double>
template class MyClass<int>;
template class MyClass<double>;

模板的总结

优点

  1. 代码重用:模板允许创建参数化的代码,从而大大减少重复代码,提高开发效率。
  2. 类型安全:模板提供编译时类型检查,确保类型正确,减少运行时错误。
  3. 性能优化:模板实例化是在编译时进行的,编译器可以针对特定的数据类型生成高效的代码。

缺点

  1. 编译时间增加:由于模板在编译时需要实例化多个版本,因此可能会增加编译时间。
  2. 代码膨胀:模板在编译时生成大量代码,可能会导致可执行文件体积增大。
  3. 易读性和调试困难:模板代码可能较为复杂,不易阅读和理解,同时在调试时也可能更加困难。
  4. 二进制兼容性问题:由于模板实例化是在编译时进行的,因此不同编译器或不同编译选项下生成的二进制代码可能不兼容。
  5. 限制:模板的某些高级特性(如局部特殊化和特殊化顺序)在不同C++标准实现中可能不统一,限制了模板的跨平台性和可移植性。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 非类型模板参数
  • 模板的特化
    • 函数模板特化
    • 类模板特化
      • 全特化
      • 偏特化
  • 模板的分离编译
    • 解决方式
  • 模板的总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档