C++ 10 模板进阶:参数特化与分离编译解析

模板

模板参数分类类型形参与非类型形参
类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称

非类型形参

非类型形参,就是用一个常量作为类**(函数)模板的一个参数,在类(函数)**模板中可将该参数当成常
量来使用

cpp 复制代码
//非类型模板参数
//宏定义也可以完成,但宏定义没有该操作自由,可以多个不一样的N
 // 注意只能是常量变量,字符 布尔值 可以   但浮点数 字符串不行
template<class T, size_t N = 10>//设立缺省值
class Array {
public:
	size_t size()const {
		return _size;
	}
	T& operator[](size_t n)
	{
		return _data[n];
	}
	T& operator[](size_t n) const
	{
		return _data[n];
	}
	bool empty()
	{
		return _size == 0;
	}
private:
	T _data[N];
	size_t _size = N;
};

模板特化

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些****错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板

函数模板特化

函数模板的特化步骤:

  1. 必须要先有一个基础的函数模板
  2. 关键字template后面接一对空的尖括号<>
  3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
  4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇 怪的错误。

通用模板及通用模板特化

模板特化分为全特化和偏特化

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

偏特化:任何针对模版参数进一步进行条件限制设计的特化版本

cpp 复制代码
//通用形式
template<class T1,class T2>
class func {
	
public:
	func(const T1& m, const T2& n)
		:_begin(m)
		, _end(n)
	{
		cout << "T1" << " " << "T2" << endl;
		cout << _begin << " " << _end<<endl;
	}

private:
	T1 _begin;
	T2 _end;
};
//全特化  设两个参数为double
template<>
class func<double,double> {
	
public:
	func(double m,double n)
		:_begin(m)
		, _end(n)
	{
		cout << "double" << " " << "double" << endl;
		cout << _begin << " " << _end<<endl;
	}

private:
	double _begin;
	double _end;
};
//偏特化 半特化
template<class T>
class func<T, double> {

public:
	func(const& m, double n)
		:_begin(m)
		, _end(n)
	{
		cout << "T" << " " << "double" << endl;
		cout << _begin << " " << _end << endl;
	}

private:
	T _begin;
	double _end;
};

指针模板特化

cpp 复制代码
//指针的特化
template<class T1,class T2>
class func<T1*,T2*> {

public:
	func(const T1& m, const T2& n)
		:_begin(m)
		, _end(n)
	{
		cout << "T1*" << " " << "T2*" << endl;
		cout << _begin << " " << _end << endl;
	}

private:
	T1 _begin;
	T2 _end;
};

引用模板特化

cpp 复制代码
//引用
template<class T1, class T2>
class func<T1&, T2&> {

public:
	func(const T1& m, const T2& n)
		:_begin(m)
		, _end(n)
	{
		cout << "T1&" << " " << "T2&" << endl;
		cout << _begin << " " << _end << endl;
	}

private:
	T1 _begin;
	T2 _end;
};

模板分离编译

什么是模板分离链接

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。

模板的分离编译示例

假如有以下场景,模板的声明与定义分离开,在头文件中进行声明,源文件中完成定义

cpp 复制代码
// a.h
template<class T>
T Add(const T& left, const T& right);
// a.cpp
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
// main.cpp
#include"a.h"
int main()
{
Add(1, 2);
Add(1.0, 2.0);
return 0;
}

会显示链接错误,原因就是模板的定义与声明分开在不同文件使用了

在main.cpp中,运行到.Add,因为包含的a.h中有Add的声明,所以不会报错,但调用Add的函数时,却错误,我们不是在a.cpp进行了Add的定义吗?

但事实上是main.cpp在调用Add的函数时,找不到地址

解决方法

  1. 定义与声明放到同一个文件上
  2. 显示实例化(不推荐)

总结:

  1. 非类型形参可以让我们在传参时更加灵活
  2. 模板特化可以为特定类型提供特定方式,有全特化和偏特化
  3. 要正确理解模板分离编译的问题所在
相关推荐
NAGNIP5 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
端平入洛13 小时前
delete又未完全delete
c++
颜酱14 小时前
单调栈:从模板到实战
javascript·后端·算法
CoovallyAIHub17 小时前
仿生学突破:SILD模型如何让无人机在电力线迷宫中发现“隐形威胁”
深度学习·算法·计算机视觉
CoovallyAIHub17 小时前
从春晚机器人到零样本革命:YOLO26-Pose姿态估计实战指南
深度学习·算法·计算机视觉
CoovallyAIHub17 小时前
Le-DETR:省80%预训练数据,这个实时检测Transformer刷新SOTA|Georgia Tech & 北交大
深度学习·算法·计算机视觉
CoovallyAIHub18 小时前
强化学习凭什么比监督学习更聪明?RL的“聪明”并非来自算法,而是因为它学会了“挑食”
深度学习·算法·计算机视觉
CoovallyAIHub18 小时前
YOLO-IOD深度解析:打破实时增量目标检测的三重知识冲突
深度学习·算法·计算机视觉
祈安_18 小时前
C语言内存函数
c语言·后端
NAGNIP1 天前
轻松搞懂全连接神经网络结构!
人工智能·算法·面试