C++模版进阶


大家好久不见,我是残念我回来了,希望在你看完之后,能对你有所帮助,有什么不足请指正!共同学习交流
本文由:残念ing原创CSDN首发,如需要转载请通知
个人主页:残念ing-CSDN博客,欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏:残念ing 的C++系列专栏——CSDN博客


请添加图片描述

1、非类型模版参数

模版参数分类类型参与非类型形参。
类型形参即:出现在模版参数列表中,跟在class或者typename之类的参数类型名称。
非类型形参:就是一个用常量作为(函数)模版的一个参数,在类(函数)模版中可将其参数当成常量来使用。

**优点:**可以灵活的使用这个常量,不会被束缚。

template <class T, size_t N>
class stack
{
private:
	int _arr[N];
	int _size;
};
int main()
{
	stack <int,10> s;
	stack <int,100> s1;
	return 0;
}

注意:c++20之前的都不可以用比如double等内置类型(除string),只允许整型来做非模版参数。

2、模板的特化

2、1 什么是模版的特化

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

举例:

template<class T>
bool Less(const T& left,const T& right)
{
	return left<right;
}
//特化--特殊处理
template <>
bool Less<Date*>(Date* const &left,Date* const &right)
{
	return *left<*right;
} 
int main()
{
	Date d1(2022,8,30);
	Date d2(2022,8,31);
	cout<<Less(d1,d2)<<endl;
	Date* p1=&d1;
	Date* p2=&d2;
	cout<<Less(p1,p2)<<endl;
	return 0;
}

上面的例子中我们可以看到在没有特化之前时,Less内部并没有比较p1和p2指向的对象内容,而比较的是p1和p2指针的地址,这就无法到达预期而错误
解决的办法:将模版进行特化。在原模版类的基础上,针对特殊类型所进行特殊化的实现方式。模版特化分为函数模版特化与类模版特化

2.2 函数模版特化

特化的步骤:
1、必须要先有一个基础的函数模版

2、关键字template后面接一对空的尖括号<>

3、函数名后跟一对尖括号,尖括号中指定需要特化的类型

4、函数形参表,必须要和模版函数的基础参数类型完全相同,如果不同编译器可能回报一些奇怪的错误。

注意:一般情况下如果函数模版遇到不能处理或者处理有误的类型,为了实现简单通常都是将函数直接给出。

bool Less(Date* left,Date* right)
{
	return *left<*right;
}

2.3 类模版特化

1、全特化

全特化即是模版参数列表中所有的参数都确定化

#pragma once

namespace bit
{
	template <class t1,class t2>
	class date
	{
	public:
		date()
		{
			cout << "date <t1,t2>" << endl;
		}
	private:
		t1 _d1;
		t2 _d2;
	};

	template<>
	class date<int,char>
	{
	public:
		date()
		{
			cout << "date<int,char>" << endl;
		}
	private:
		int _d1;
		char _d2;
	};
}

2、偏特化

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

//部分特化—将模版参数类表中的一部分参数特化
	template<class t1>
	class date<t1, int>
	{
	public:
		date()
		{
			cout << "date<t1,int>" << endl;
		}
	private:
		t1 _d1;
		char _d2;
	};

	//参数更进一步的限制
	template <typename t1,typename t2>
	class date<t1*, t2*>
	{
	public:
		date()
		{
			cout << "date<t1*,t2*>"<<endl;
		}
	private:
		t1 _d1;
		t2 _d2;
	};


	template <typename t1,typename t2>
	class date<t1&, t2&>
	{
	public:
		date(const t1& d1,const t2& d2)
			:_d1(d1)
			,_d2(d2)
		{
			cout << "date<t1&,t2&>" << endl;
		}
	private:
		const t1& _d1;
		const t2& _d2;
	};

使用实例:

#include<vector>
#include <algorithm>
template<class T>
struct Less
{
bool operator()(const T& x, const T& y) const
{
	return x < y;
}
};
int main()
{
	Date d1(2022, 7, 7);
	Date d2(2022, 7, 6);
	Date d3(2022, 7, 8);
	vector<Date> v1;
	v1.push_back(d1);
	v1.push_back(d2);
	v1.push_back(d3);
	// 可以直接排序,结果是日期升序
	sort(v1.begin(), v1.end(), Less<Date>());
	vector<Date*> v2;
	v2.push_back(&d1);
	v2.push_back(&d2);
	v2.push_back(&d3);
	// 可以直接排序,结果错误日期还不是升序,而v2中放的地址是升序
	// 此处需要在排序过程中,让sort比较v2中存放地址指向的日期对象
	// 但是走Less模板,sort在排序时实际比较的是v2中指针的地址,因此无法达到预期
	sort(v2.begin(), v2.end(), Less<Date*>());
	return 0;
}

结果分析:
sort最终按照Less模版中方式比较,所以只会比较指针,而不是比较指针指向空间中的内容。
解决办法:

// 对Less类模板按照指针方式特化
template<>
struct Less<Date*>
{
	bool operator()(Date* x, Date* y) const
	{
		return *x < *y;
	}
};

3、模版分离编译

3.1 什么是分离编译

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

3.2使用场景

//add .h
template <class T>

const T& add(const T& left,const T& right);



//add.cpp
#include<add.h>
template <class T>
const T& add(const T& left,const T& right)
{
	return letf+right;
}


//test.cpp
#include<add.h>
int main()
{
	add(1,2);
	add(1.1,2.2);
	return 0;
}

结果分析:
add不会被编译,生成指令,因为模版没有被实例化,当然也就没有add的地址放进符合表,所以链接也就找不到。
解决的办法:
1、将声明和定义放到一个.cpp文件里面或者.h文件也可以的
2、模版定义的位置显示实例化。

推荐阅读文献:https://blog.csdn.net/pongba/article/details/19130

总结

优点:
1、模版复用了代码,节省资源,更快的迭代开发,C++的标准模版板库(STL)因此而产生
2、增强了代码的灵活性

缺陷:
1、模版会导致代码膨胀问题,也会导致编译时间变长
2、出现模版编译错误时,错误信息非常凌乱,不易定位错误

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值