模板进阶

非类型模板参数

非类型模板参数介绍

模板参数分为类类型和与非类型参数,像我们之前介绍的就是类型模板参数

cpp 复制代码
template<class T>   //类类型模板参数
class vector
{
private:
    int *_arr;
    int  _size;
    int  _capacity;

};

非类类型模板参数,就是就是用一个常量作为模板参数,比如我们要定义一个静态的栈,即栈的容量为固定值,像下面这样定义一个固定容量为100的栈

cpp 复制代码
#define N 100

template<class T>
class stack
{
private:
	T _arr[N];
	T _top;
};

int main()
{
	stack<int> st;     //定义一个大小只有100的栈
	return 0;
}

那要在这个的基础上面再定义一个大小为10的栈怎么办嘞,再重新定义一个,那大小为1000的嘞,再定义一个?这样是不是太不方便了,这时候就需要用到我们的非类型模板参数,像下面这样

cpp 复制代码
template<class T,size_t N=100>    //这里也是可以給缺省值的
class stack
{
public:
	stack()
	{
		cout << "stack()" << endl;
	}
private:
	T _arr[N];
	T _top;
	
};

int main()
{
	stack<int> st;         //大小为缺省值,100
	stack<int, 10> st1;    //定义一个大小为10的栈
	stack<int, 20> st2;    //定义一个大小为20的栈
	
	return 0;
}

这就是我们的非类型模板参数,但是需要注意的是,里面的非类型模板参数不可以使用自定义类型,比如string之类的,甚至有时候浮点数也是不可以用的,比如下面

cpp 复制代码
template<class T,string s>
class A
{
};


int main()
{
	return 0;
}

//有的编译器再编译的时候是不会报错的,只有你在调用的时候会出错,因为按需实例化,
//加上这句话 stack<int,"1111">就会报错了

array类型介绍

array类型是对数组进行封装,使用的格式

比如

cpp 复制代码
#include<array>

int main()
{
	array<int, 10> arr1;   //定义大小为10的数组
	return 0;
}

但是为啥有了数组,还要弄一个这个对数组的封装嘞,因为普通数组对越界检查不是很严格的,

在上面的程序中,我们定义了一个大小为10的数组,但是我们越界访问了第15个位置,编译器没有报错,这就说明,普通数组对越界访问的检查并不是很严格的,但是我们的array是非常严格的

但是array的也是有缺陷的,比如下面的

cpp 复制代码
#include<array>
#include<vector>

int main()
{
	array<int, 10> arr;
	vector<int> v(10);    //定义大小为10的vector
	cout << "sizeof(arr)" << sizeof(arr) << endl;
	cout << "sizeof(v)" << sizeof(v) << endl;
	return 0;
}


//运行结果为   40 
          //   32

同样容量大小的vector和array,array占用的大小更大,这就说明array设计的并不是很好,所以用array不如用vector,再这里介绍array只是当作了解,实际运用中并不会用太多

模板的特化

函数模板的特化

下面我们用一个例子来介绍今天的特化

cpp 复制代码
namespace LiHao                    //避免和标准库中的less函数进行冲突
{
	template<class T>
	bool less(T x, T y)
	{
		return x < y;
	}

}

int main()
{
	int x = 10, y = 20;

	int* px = &x, * py = &y;
	cout << LiHao::less(x, y)<<endl;           //运行结果:1  
    cout << LiHao::less(px, py) << endl;       //运行结果:1
	return 0;
}

上面的程序中,我们用指针传递指针参数是想要比较他们指向的内容,但是程序是比较了两个指针指向的地址的大小,这并不是我们的本意,想要比较他们所指向的内容的大小,该怎么办嘞,这个时候就需要用到模板的特化,可以像下面这样

cpp 复制代码
template<>                            //这个语句是必须写
	bool less<int*>(int* x, int* y)
	{
		return *x < *y;
	}

这就是函数模板的特化,但是函数模板的特化有很多坑,比如下面的这个

cpp 复制代码
template<class T>
	bool less(const T& x,const T& y)
	{
		return x < y;
	}

	template<>
	bool less<int*>(int* const& x, int* const& y)
	{
		return *x < *y;
	}

如果第一个模板里面加上const的话,模板的特化也必须加上const,但是,有时候我们会加错const的位置,比如

cpp 复制代码
template<class T>
	bool less(const T& x,const T& y)
	{
		return x < y;
	}

	template<>
	bool less<int*>(const int*& x, const int*& y)    //这样是错误的,上面的const修饰的是x
	{                                                //和y,这下面就应该修饰指针x和y,
		return *x < *y;                              //const *p修饰的是p指向的内容,*const 
	}                                                //p修饰的才是指针本身

类模板的特化

全特化是指类模板里面的参数全部都确定

部分特化是部分参数确定化

cpp 复制代码
namespace LiHao
{

	template<class T1, class T2>
	class data
	{
	public:
		data()
		{
				cout << "template<class T1,class T2>正常模式" << endl;
		}
	private:
		T1 _data1;
		T2 _data2;
	};

	template<class T1>       //部分特化,偏特化
	class data<T1, int>
	{
	public:
		data()
		{
			cout << "template<class T1>偏特化" << endl;

	private:
		T1 _data1;
		int _data2;
	};


}

int main()
{
	LiHao::data<double, double> d1;
	LiHao::data<int, int> d2;
	return 0;
}
		

运行结果

还可以限定类模板类型,比如下面的

cpp 复制代码
template<class T1, class T2>
class data<T1*, T2*>
{
public:
	data()
	{
		cout << "class data<T1*,T2*>" << endl;
	}
};


int main()
{
    Data<int *,int **> d1;
    return 0;
}

运行结果

关于模板申明和定义不能分离

在之前vector和list的模拟实现当中,我们的声明和定义都是写在头文件当中的,一旦声明和定义分离,写在不同的文件当中,运行的时候会出现链接错误,现在我们来说明一下为什么会出现链接错误

我们在调用一个函数的时候,底层是去call一个函数,转到函数地址哪里去执行,函数的地址就是函数定义的地方的第一句代码的地址,如果函数定义和声明的地方不同,编译器知道函数要实例化成什么,但是没有定义,而函数定义的地方,不知道实例化成什么,因为没有被实例化而不会被编译,当然也就没有函数的地址放进符号表,因而编译器找不到函数的地址出现链接错误

相关推荐
山风wind2 小时前
Spring中责任链模式的工业级应用简单剖析
java·spring·责任链模式
慕容青峰2 小时前
【加拿大计算机竞赛 CCO 小行星采矿】题解
c++·算法·sublime text
Ghost-Silver2 小时前
2025年度总结
开发语言·数据结构·c++·算法
Element_南笙2 小时前
BUG:ModuleNotFoundError: No module named ‘milvus_lite‘
java·服务器·数据库
你撅嘴真丑2 小时前
成绩排序 与 整数奇偶排序
数据结构
yyy(十一月限定版)2 小时前
C++基础
java·开发语言·c++
Coder_Boy_2 小时前
分布式系统设计经验总结:金融vs电商的核心差异与决策思路
java·运维·微服务·金融·电商
谈笑也风生2 小时前
经典算法题型之排序算法(四)
数据结构·算法·排序算法
AI科技星2 小时前
空间螺旋电磁耦合常数 Z‘:拨开迷雾,让电磁力变得直观易懂
服务器·人工智能·科技·算法·生活