C++模板进阶(非类型模板参数 + 模板特化)

我们另一篇模板初阶介绍链接:http://t.csdn.cn/Ox8Dm

目录

 一、非类型模板参数

1.1 非类型模板参数概念

1.2 模板类型的静态数组 

二、模板特化

2.1 函数模板特化

2.2 类模板特化

2.2.1 类模板全特化

2.2.2 类模板半特化(偏特化)

 2.2.3模板特化应用场景


 一、非类型模板参数

1.1 非类型模板参数概念

模板参数分为类型参数和非类型参数!

类型参数就是出现在模板参数列表中,跟在class 或者typename之类的参数类型名称。

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

1.2 模板类型的静态数组 

将数组封装成类,类成员是一个数组!我们可以通过传非类型模板参数定义数组的大小!这样我们手动调控静态数组大小!

template
class Array
{
public:
	Array()
	{
		for (size_t i = 0;i <_size;i++)
		{
			_arr[i] = i+1;
		}
	}
	T operator[](size_t n)
	{
		assert(n < _size);//只要发生越界直接报错
		return _arr[n];
	}
	size_t size()const
	{
		return _size;
	}
private:
	T _arr[N];
	size_t _size=N;
};

测试一下效果:

C++模板进阶(非类型模板参数 + 模板特化)_第1张图片


二、模板特化

2.1 函数模板特化

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

我们实现了一个比较模板函数,下面我们预比较不同类型的数据:

//模板函数
template
bool Less(const T& left, const T& right)
{
	return left < right;
}

void Test2()
{
    //整形
	cout << " Less(1, 2)="<

很明显我们发现同样希望比较日期类,第二个比较直接用Date类型,第三个用的是Date*,但是比较结果却相反!这与我们的期望不同!思考发现,原来第三个比较的并不是日期类,而是二者的地址,所以结果不同!这种情况下,我们理想的是比较*left与*right,但是模板函数参数限定了它的比较形式!也就是说范式的模板函数不能解决所有的比较,我们需要特例化!也就是特化函数模板!这里我们需要特化Date*比较!

函数模板的特化步骤:

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

特化Date* 代码:

template
bool Less(const T& left, const T& right)
{
	return left < right;
}

template<>//这个模板列表不能省去!
bool Less(Date* const& left, Date* const& right)
{
	return *left < *right;
}

特化后比较结果:


2.2 类模板特化

2.2.1 类模板全特化

template
class Data
{
public:
	Data() { cout << "Data" << endl; }
private:
	T1 _d1;
	T2 _d2;
};

//类模板全特化,也就是模板参数都确定化
template<>
class Data
{
public:
	Data() { cout << "Data" << endl; }
private:
	int _d1;
	char _d2;
};

//全特化测试
void Test3()
{
	Data d1;
	Data d2;
}

 C++模板进阶(非类型模板参数 + 模板特化)_第2张图片

若模板参数匹配特化的类模板参数,则优先调用特化类模板!


2.2.2 类模板半特化(偏特化)

偏特化就是部分类模板参数具体化!如果类模板所传参数满足特化模板对应位置具体化参数!则优先调用特化模板!

//一般模板函数
template
class Data
{
public:
	Data() { cout << "Data" << endl; }
private:
	T1 _d1;
	T2 _d2;
};

//偏特化,部分位置参数确定
template 
class Data
{
public:
	Data() { cout << "Data" << endl; }
private:
	T1 _d1;
	int _d2;
};

//指针/引用偏特化
template 
class Data 
{
public:
	Data() { cout << "Data" << endl; }
private:
	T1 _d1;
	T2 _d2;
};

template 
class Data 
{
public:
	Data(const T1& d1, const T2& d2)
		: _d1(d1)
		, _d2(d2)
	{
		cout << "Data" << endl;
	}
private:
	const T1& _d1;
	const T2& _d2;
};

//偏特化测试
void Test4()
{
	Data d1; // 调用特化的int版本
	Data d2; // 调用基础的模板
	Data d3; // 调用特化的指针版本
	Data d4(1, 2); // 调用特化的指针版本
}

 C++模板进阶(非类型模板参数 + 模板特化)_第3张图片


 2.2.3模板特化应用场景

如果我们拿到的类型是日期类的地址,我们想要less比较的是*left和*right !但库中的一般模板参数只是比较left和right!也就是只比较地址!这样不能满足我们的需求,所以必须特化!

#include
#include//sort
#include //less
//模板特化应用场景
template<>
class less
{
public:
	bool operator()(Date* left,Date* right)
	{
		return *left > *right;
	}
};
void Test5()
{
	Date d1(2023, 1, 8);
	Date d2(2023, 1, 9);
	Date d3(2022, 12, 31);
	vector v;
	v.push_back(&d1);
	v.push_back(&d2);
	v.push_back(&d3);
	sort(v.begin(), v.end(), less());
	for (auto& e : v)
	{
		cout << *e;
	}
}

C++模板进阶(非类型模板参数 + 模板特化)_第4张图片


你可能感兴趣的:(STL,C++,数据结构)