【c++】模板进阶

1. 非类型模板参数

定义一个数组类

#include<iostream>
using namespace std;
#define N   1000
namespace zjw
{   
	// 定义一个模板类型的静态数组
	template<class T>
	class array
	{
	public:
		T& operator[](size_t index) { return _array[index]; }
		const T& operator[](size_t index)const { return _array[index]; }

		size_t size()const { return _size; }
		bool empty()const { return 0 == _size; }

	private:
		T _array[N];
		size_t _size=N;
	};
}

我们需要两个对象,分别数组大小为10,和1000的话,只用上面一个类是不够的,两个类给不同的N值.

这里我们可以用非类型模板参数来解决这个问题,只需要一个类。
在这之前有一个知识点

#include<iostream>

using namespace std;
#include<iostream>
using namespace std;
#define N   1000
namespace zjw
{
	// 定义一个模板类型的静态数组
	template<class T>
	class array
	{
	public:
		T& operator[](size_t index) { return _array[index]; }
		const T& operator[](size_t index)const { 
			size(1);//这里故意写错
			return _array[index]; }

		size_t size()const { return _size; }
		bool empty()const { return 0 == _size; }

	private:
		T _array[N];
		size_t _size = N;
	};
}

int main()
{

	zjw::array<int>st1;
	cout << st1.size() << endl;


}

size(1);//这里故意写错,但是在实例化st1,它只对要用的函数实例化,并不会检查其他类成员函数内部有没有错误。在operator[]中,size(1);//这里故意写错,就不会报错。而编译器只会对大体的结构进行检查,比如说哪个类成员函数少一个分号。

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

#include<iostream>
using namespace std;

namespace zjw
{
	// 定义一个模板类型的静态数组
	template<class T, size_t N = 10>
	class array
	{
	public:
		T& operator[](size_t index) { return _array[index]; }
		const T& operator[](size_t index)const { return _array[index]; }

		size_t size()const { return _size; }
		bool empty()const { return 0 == _size; }

	private:
		T _array[N];
		size_t _size=N;
	};
}

在这里插入图片描述

在这里插入图片描述

浮点数、类对象以及字符串是不允许作为非类型模板参数的。c++20可以
非类型的模板参数必须在编译期就能确认结果。

#include<iostream>
using namespace std;

namespace zjw
{
	
	template<string str>
     class A
   { 

    };

}
int main()
{
	zjw::A<"11111">st3;

}

在这里插入图片描述

2. 类模板的特化

上篇文章我们使用仿函数来给日期类比较大小,现在我们可以使用函数模板来给日期类比较大小
先定义一个日期类

class Date
{
public:
	friend ostream& operator<<(ostream& _cout, const Date& d);

	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}

	bool operator>(const Date& d)const
	{
		return (_year > d._year) ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}
private:
	int _year;
	int _month;
	int _day;
};

然后实现函数模板比较大小

 函数模板
template<class T>
bool Less(T left, T right)
{
	

	return left < right;
}

主函数

int main()
{

	Date d1(2024, 2, 10);
	Date d2(2024, 3, 10);
	cout << Less(d1, d2) << endl;



}

在这里插入图片描述

此时d1<d2返回1.
实例化过程如下:
在这里插入图片描述


如果我们要给日期类指针进行比较大小
在这里插入图片描述
这里我们可以用特化

函数模板的特化步骤:

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

	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}

	bool operator>(const Date& d)const
	{
		return (_year > d._year) ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}
private:
	int _year;
	int _month;
	int _day;
};
template<class T>
bool Less(T left, T right)
{
return left < right;
}
// 特化,针对某些特殊类型可以进行特殊处理
template<>
bool Less<Date*>(Date* left, Date* right)
{
	return *left < *right;
}
int main()
{
	Date d1(2024, 2, 10);
	Date d2(2024, 3, 10);
	Date* p1 = new Date(2022, 7, 7);
	Date* p2 = new Date(2022, 7, 8);
   cout << Less(p1,p2) << endl;
}

在这里插入图片描述

或者这样类似函数重载,匹配最符合的,有现成的使用现成的

template<class T>
bool Less(T left, T right)
{
return left < right;
}

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

特化,针对某些特殊类型可以进行特殊处理

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

template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};
// 全特化
template<>
class Data<int, char>
{
public:
	Data() { cout << "Data<int, char>" << endl; }
};
int main()
{
	
		
		Data<int, char> d2;
		

}

半特化->部分特化
将模板参数类表中的一部分参数特化。


template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};
// 半特化/偏特化
template<class T1>
class Data<T1, char>
{
public:
	Data() { cout << "Data<T1, char>" << endl; }
};

半特化->参数更进一步的限制
偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版
本。

template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};
// 半特化/偏特化,不一定是特化部分参数,可能是对参数的进一步限制
template<class T1, class T2>
class Data<T1*, T2*>
{
public:
	Data() { cout << "Data<T1*, T2*>" << endl; }
};
template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};
template<class T1, class T2>
class Data<T1&, T2*>
{
public:
	Data() { cout << "Data<T1&, T2*>" << endl; }
};

5. 模板的分离编译

首先声明定义不分离:不会出现问题
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
声明定义分离:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
链接出现问题,原因是在源.cpp中调用st1.size()会call这个函数的地址,在编译时候,去array.h中发现他只有声明,编译器会以为函数地址会在其他cpp中,等到链接的时候在call size函数地址,但是等到链接时,在cpp之间是分离的,,所以源.cpp中st1实例化的参数<int,10>不会给array.cpp中<T,N>;模板没有实例化,所以array.cpp中的size()函数没有地址,出现了链接错误。
解决方法:显示实例化
在这里插入图片描述
反汇编观察size()函数地址,call size()函数地址说明要调用该函数

在这里插入图片描述

相关推荐

  1. C++:模板

    2024-04-21 00:54:07       47 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-21 00:54:07       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-21 00:54:07       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-21 00:54:07       82 阅读
  4. Python语言-面向对象

    2024-04-21 00:54:07       91 阅读

热门阅读

  1. Android 单一音量控制

    2024-04-21 00:54:07       34 阅读
  2. Spark面试整理-Spark集成Hive

    2024-04-21 00:54:07       31 阅读
  3. 4月20日,每日信息差

    2024-04-21 00:54:07       33 阅读
  4. Python框架django项目

    2024-04-21 00:54:07       34 阅读
  5. oepncv android 使用笔记

    2024-04-21 00:54:07       35 阅读
  6. 使用leaflet给地图添加蒙版(超级详细免费看)

    2024-04-21 00:54:07       39 阅读
  7. 个人开发者,Spring Boot 项目如何部署

    2024-04-21 00:54:07       34 阅读
  8. HttpServletResponse HttpServletRequest

    2024-04-21 00:54:07       32 阅读