C++第九讲:模板进阶

1.非类型模板参数

我们平时定义的模板参数都是类型模板参数,而非类型模板参数值的是整形常量,在C++20标准中,也支持了浮点数的定义:

//非类型模板参数
//比如说我们要定义一个静态的栈:
template<class T, size_t N = 10>
//template<class T, double N = 10>//err:常量表达式不是整形
//template<class T, char N = 10>
class Stack
{
    
    
private:
	T _a[N];
	int top;
};

int main()
{
    
    
	Stack<int, 20> st1;
	Stack<int> st2;
	Stack<int, 100> st3;

	return 0;
}

比如说我们昨天看的那个deque中就看到了非类型模板参数的应用
在这里插入图片描述
C++11也新加了一个array的东西,这个array是一个静态数组,我们看下面:
在这里插入图片描述

2.模板的特化

//我们实现了一个很简单的比较函数模板
template<class T>
bool Less1(T left, T right)
{
    
    
	return left < right;
}

int main()
{
    
    
	cout << Less1(1, 2) << endl;//可以正常比较

	Date d1(2023, 10, 11);
	Date d2(2023, 12, 11);
	cout << Less1(d1, d2) << endl;//可以正常比较

	return 0;
}

但是,我们这样改一下:

int main()
{
    
    
	cout << Less1(1, 2) << endl;//可以正常比较

	Date d1(2023, 10, 11);
	Date d2(2023, 12, 11);
	cout << Less1(d1, d2) << endl;//可以正常比较

	Date* p1 = new Date(2024, 10, 11);
	Date* p2 = new Date(2024, 12, 11);
	cout << Less1(p1, p2) << endl;

	return 0;
}

可以看出,这就成了比较地址了,就没有正确性可言了,所以我们要使用模板的特化来解决这个问题:

//我们实现了一个很简单的比较函数模板
template<class T>
bool Less1(T left, T right)
{
    
    
	return left < right;
}

//模板的特化
template<>
bool Less1<Date*>(Date* d1, Date* d2)
{
    
    
	return *d1 < *d2;
}

int main()
{
    
    
	cout << Less1(1, 2) << endl;//可以正常比较

	Date d1(2023, 10, 11);
	Date d2(2023, 12, 11);
	cout << Less1(d1, d2) << endl;//可以正常比较

	Date* p1 = new Date(2024, 10, 11);
	Date* p2 = new Date(2024, 12, 11);
	cout << Less1(p1, p2) << endl;

	return 0;
}

但是特化有一个比较麻烦的点:

//我们实现了一个很简单的比较函数模板
template<class T>
bool Less1(const T& left, const T& right)
{
    
    
	return left < right;
}

//模板的特化
template<>
bool Less1<Date*>(Date* d1, Date* d2)//err:不是函数模板的专用化
{
    
    
	return *d1 < *d2;
}

当我们Less1的实现参数为const &类型时,会发生报错,因为特化要保持和模板的性质类似,那么我们可能会这样写:

//模板的特化
template<>
bool Less1<Date*>(const Date*& d1, const Date*& d2)//err:不是函数模板的专用化
{
    
    
	return *d1 < *d2;
}

还是不对,因为const Date*& d1中的const修饰的是*d1,而模板参数中的const修饰的是left本身,所以我们要将const改一个位置:

//模板的特化
template<>
bool Less1<Date*>(Date* const& d1, Date* const& d2)//err:不是函数模板的专用化
{
    
    
	return *d1 < *d2;
}

3.类模板的特化

3.1全特化

如果我们将模板参数全部都特化的话,就叫做全特化:

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;
};
int main()
{
    
    
	Date<int, int> d1;//Date<T1, T2>
	Date<int, char> d2;//Date<int, char>

	return 0;
}

3.2偏特化

偏特化就是特化部分参数,有两种:

扫描二维码关注公众号,回复: 17489430 查看本文章

3.2.1将模板参数表中的一部分参数特化

//将第二个参数特化为int
template <class T1>
class Data<T1, int>
{
    
    
public:
	Data() {
    
     cout << "Data<T1, int>" << endl; }
private:
	T1 _d1;
	int _d2;
};

3.2.2参数进一步的限制

偏特化不仅仅是指特化部分参数,还可以是对参数的限制:

//两个参数偏特化为指针类型 
template <typename T1, typename T2>
class Data <T1*, T2*>
{
    
    
public:
	Data() {
    
     cout << "Data<T1*, T2*>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};
//两个参数偏特化为引用类型
template <typename T1, typename T2>
class Data <T1&, T2&>
{
    
    
public:
	Data(const T1& d1, const T2& d2)
		: _d1(d1)
		, _d2(d2)
	{
    
    
		cout << "Data<T1&, T2&>" << endl;
	}
private:
	const T1& _d1;
	const T2& _d2;
};
void test2()
{
    
    
	Data<double, int> d1;//调用特化的int版本
	Data<int, double> d2;//调用基础的模板
	Data<int*, int*> d3;//调用特化的指针版本
	Data<int&, int&> d4(1, 2);//调用特化的指针版本
}

4.模板分离编译

4.1什么是分离编译

我们在实现之前的类之前,都是按照声明和定义分离分离来实现的,但是模板类的实现时,会有问题,我们下面来看一下模板类实现问题的原因

4.2为什么模板类不能够实现分离编译

在这里插入图片描述

5.模板总结

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/2301_79761834/article/details/143233537