C++:array,模板特化 详解

目录

一.容器array

1.介绍

2.array和vector比较

 3.array和原生数组比较——array唯一优势:有越界检查

 4.总结建议:用vector别用array

5.非类型模板参数

(1)非类型模板参数是常量,不可修改

 (2)非类型模板参数一般就是整形。

二.模板的特化

1.函数模板特化

2.类模板特化

1.介绍

2.示例2:仿函数的偏特化使用


一.容器array

1.介绍

 固定长度的顺序容器,就是定长数组

2.array和vector比较

vector是动态开辟的,放在堆上的,且内部存的是指针;array就是个定长数组,放在栈上的,内部存的就是个数组

 3.array和原生数组比较——array唯一优势:有越界检查

array相比原生数组唯一优势:有越界检查,因为有[]运算符重载,[]运算符重载中有assert检查。

 4.总结建议:用vector别用array

array对比原生数组,还是有一些越界检查的优势的。但是实际中我们统一直接用vector更香!

5.非类型模板参数

(1)非类型模板参数是常量,不可修改

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

 (2)非类型模板参数一般就是整形。

整形int,char,unsigned int等。
1.浮点数、类对象以及字符串是不允许作为非类型模板参数的。
2.非类型的模板参数必须在编译期就能确认结果。

二.模板的特化

1.函数模板特化

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

 针对某些类型要特殊化处理
template<>
bool Less<Date*>(Date* left, Date* right)    //模板特化
{
	return *left < *right;
}

bool Less(Date* left, Date* right)    //原生函数
{
	return *left < *right;
}


 函数模板基本不用特化方式处理,直接写一个具体类型的函数更好、
int main()
{
	cout << Less(1, 2) << endl;   // 可以比较,结果正确

	Date d1(2022, 7, 7);
	Date d2(2022, 7, 8);
	cout << Less(d1, d2) << endl;  // 可以比较,结果正确

	Date* p1 = new Date(2022, 7, 16);
	Date* p2 = new Date(2022, 7, 15);
	cout << Less(p1, p2) << endl;  // 可以比较,结果正确 3.

	return 0;
}

正常的Less(d1, d2)比较日期类大小, 传进left < right后按照Date中的<运算符重载进行比较,但是Less(p1, p2)传的是指针,如果用模板函数会比较指针,所以这里用到模板特化函数去设置形参是Date*时比较*left < *right,类似于上面这种,就叫模板特化。当然也可以直接写出原生的函数,在没有原生函数的条件下,第3个Less(p1, p2)会优先调用模板特化函数,有原生函数会优先调用原生函数,在函数模板中是可以并存的,类模板中这样没法用。所以结论是:函数模板没必要特化,直接用原生函数就行

2.类模板特化

1.介绍

全特化即是将模板参数列表中所有的参数都确定化
 半特化/偏特化 :
1、将模板参数类表中的一部分参数特化。
2、偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来
template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};

// 全特化 :全特化即是将模板参数列表中所有的参数都确定化
template<>
class Data<int, double>
{
public:
	Data() { cout << "Data<int, double>" << endl; }
};

// 半特化/偏特化 1:
// 1、将模板参数类表中的一部分参数特化。
template<class T1>
class Data<T1, char>
{
public:
	Data() { cout << "Data<T1, char>" << endl; }
};

// 半特化的写法2:
// 2、偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来
//的一个特化版本。
template<class T1, class T2>
class Data<T1*, T2*>
{
public:
	Data() { cout << "Data<T1*, T2*>" << endl; }
};

// 半特化的写法3:
template<class T1, class T2>
class Data<T1&, T2&>
{
public:
	Data() { cout << "Data<T1&, T2&>" << endl; }
};

int main()
{
	Data<int, int> d1;
	Data<int, double> d2;
	Data<int, char> d3;
	Data<char, char> d4;
	Data<int*, int*> d5;
	Data<int*, char*> d6;
	Data<int*, string*> d7;
	Data<int*, void*> d8;
	Data<int*, int> d9;
	Data<int&, char&> d10;

	return 0;
}

2.示例2:仿函数的偏特化使用

#include<vector>
#include <algorithm>

template<class T>
struct Less            //模板函数
{
	bool operator()(const T& x, const T& y) const
	{
		return x < y;
	}
};

//template<>   这样写只能传Date*,所以不如干脆写个偏特化可以传任何指针类型
//struct Less<Date*>
//{
//	bool operator()(Date* x, Date* y) const
//	{
//		return *x < *y;
//	}
//};

// 偏特化
template<class T>    //模板偏特化函数
struct Less<T*>
{
	bool operator()(T* x, 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*>());

	vector<int*> v3;
	v3.push_back(new int(3));
	v3.push_back(new int(1));
	v3.push_back(new int(2));
	sort(v3.begin(), v3.end(), Less<int*>());

	return 0;
}

v1使用模板函数,v2,v3使用模板偏特化函数。

猜你喜欢

转载自blog.csdn.net/zhang_si_hang/article/details/126126473