模板全特化、偏特化(局部特化)

本文深入探讨C++中的类模板特化和偏特化,包括全特化、成员函数特化、参数数量偏特化和参数范围偏特化。通过示例代码展示了如何对模板进行特化处理,以及特化版本和泛化版本的选择优先级。同时,文章还提到了函数模板的全特化,并解释了全特化函数模板与函数重载的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

特化反义就是泛化,泛化:模板,可以随便指定类型
特化:对特殊的类型(类模板参数)进行特殊的对待

一、类模板特化

1.1类模板全特化

a)常规全特化

必须先有泛化版本才能存在特化版本。只要涉及特化,一定先存在泛化。
特化版本代码编译器会优先选择。

#include <iostream>
#include <map>

using namespace std;

template<typename T, typename U>
struct TC//泛化的TC类模板
{
	void functest()
	{
		cout << "泛化版本" << endl;
	}
};

template<>//全特化:所以类型模板参数都用具体类型代表,所以这里的template后面<>为空
struct TC<int, int>//上面的T绑定到这里第一个int,U绑定第二个int
{
	//对特化版本做单独处理
	void functest()
	{
		cout << "int,int的特化版本" << endl;
	}
};

template<>//全特化:所以类型模板参数都用具体类型代表,所以这里的template后面<>为空
struct TC<double, int>
{
	//对特化版本做单独处理
	void functest()
	{
		cout << "int,int的特化版本" << endl;
	}
};

int main()
{
	TC<char, int>tcchar;
	tcchar.functest();//泛化版本

	TC<int, int>tcint;
	tcint.functest();//特化版本

	return 0;
}
泛化版本
int,int的特化版本

b)特化成员函数而不是模板

看如下代码

#include <iostream>

using namespace std;

template<typename T, typename U>
struct TC//泛化的TC类模板
{
	TC()
	{
		cout << "泛化版本构造函数" << endl;
	}

	void functest()
	{
		cout << "泛化版本" << endl;
	}
};

template<>//全特化:所以类型模板参数都用具体类型代表,所以这里的template后面<>为空
struct TC<int, int>//上面的T绑定到这里第一个int,U绑定第二个int
{
	TC()
	{
		cout << "int,int特化版本构造函数" << endl;
	}

	//对特化版本做单独处理
	void functest()
	{
		cout << "int,int的特化版本" << endl;
	}
};

template<>//全特化:所以类型模板参数都用具体类型代表,所以这里的template后面<>为空
void  TC<double, int>::functest()
{
	//对特化版本做单独处理
	cout << "double,int的特化版本的成员函数" << endl;
};

int main()
{
	TC<double, int>ditest;
	ditest.functest();

	return 0;
}
泛化版本构造函数
double,int的特化版本的成员函数

1.2类模板的偏特化(局部特化)

偏特化从两个方面说起:一个是从模板参数数量,一个是模板参数范围

模板参数数量偏特化

#include <iostream>

using namespace std;

template<typename T, typename U, typename W>
struct TC//泛化的TC类模板
{
	void functest()
	{
		cout << "泛化版本" << endl;
	}
};
//偏特化:从参数上进行偏特化,绑定2个类型模板,留一个类型模板参数
template<typename U>//因为另外两个被我绑定到具体类型,所以这里留一个U类型模板参数
struct TC<int, U, int>
{
	//对特化版本做单独处理
	void functest()
	{
		cout << "偏特化int,int版本" << endl;
	}
};


int main()
{
	TC<double, double, double>itest;
	itest.functest();

	TC<int, double, int>iditest;
	iditest.functest();

	return 0;
}
泛化版本
偏特化intint版本

模板参数范围特化

模板参数范围特化:int, const int(比int小)
原来T,现在T*(从任意类型T缩小为指针类型T*)
原来是T,现在T&左值引用,或者现在是T&&(右值引用),都叫范围缩小

#include <iostream>

using namespace std;

template<typename T>
struct TC//泛化的TC类模板
{
	void functest()
	{
		cout << "泛化版本" << endl;
	}
};
//偏特化:模板参数范围上的特化版本
template<typename T>
struct TC<const T>//const的特化版本
{
	//对特化版本做单独处理
	void functest()
	{
		cout << "偏特化const版本" << endl;
	}
};
template <typename T>
struct TC<T *>//T* 的特化版本
{
	void functest()
	{
		cout << "const T*特化版本" << endl;
	}
};
template <typename T>
struct TC<T &>//T* 的特化版本
{
	void functest()
	{
		cout << "T &左值引用特化版本" << endl;
	}
};

template <typename T>
struct TC<T &&>//T* 的特化版本
{
	void functest()
	{
		cout << "T &&右值引用特化版本" << endl;
	}
};



int main()
{
	TC<double> td;
	td.functest();

	TC<const double> td2;
	td2.functest();

	TC<double *> tpd;
	tpd.functest();

	TC<const double *> tpd2;
	tpd2.functest();

	TC<int &>tcyi;
	tcyi.functest();

	TC<int &&>tcyi2;
	tcyi2.functest();

	return 0;
}
泛化版本
偏特化const版本
const T*特化版本
const T*特化版本
T &左值引用特化版本
T &&右值引用特化版本

全特化:特化完了就是一个具体的类了。
局部特化:特化完后它本质上还是个模板。

函数模板特化

函数模板只能全特化,不能偏特化

#include <iostream>

using namespace std;

template<typename T,typename U>
void functest(T &tmprv, U&tmprv2)
{
	cout << "泛化版本" << endl;
	cout << tmprv << endl;
	cout << tmprv2 << endl;
}

template<>
void functest(int &tmprv, int &tmprv2)
{
	cout << "---------begin--------" << endl;
	cout << "functest特化版本int,int" << endl;
	cout << tmprv << endl;
	cout << tmprv2 << endl;
	cout << "----------end---------" << endl;
}

int main()
{
	const char *p = "I Love China!";
	int i = 12;
	functest(p, i);

	int j = 13;
	functest(i, j);

	return 0;
}
泛化版本
I Love China!
12
---------begin--------
functest特化版本int,int
12
13
----------end---------

全特化函数模板实际上等价于实例化 一个函数模板,并不是等价于一个函数重载

void functest<int ,int>(int &, int &){};//全特化,等价于实例化一个函数模板
void functest(int &tmprv, int &tmprv2);//重载长这样

但是在调用时候都是functest(i, j)那么编译器会执行那个函数呢,在以上代码中加入重载函数,其它不变

void functest(int &tmprv, int &tmprv2)
{
	cout << "functest重载函数" << endl;
}

int main()
{
	const char *p = "I Love China!";
	int i = 12;
	functest(p, i);

	int j = 13;
	functest(i, j);

	return 0;
}
泛化版本
I Love China!
12
functest重载函数

结果发现优先调用重载函数,编译器选择->普通->特化->泛化
关于模板特化版本 放置位置建议:

  1. 模板定义、实现都放在一个.h文件中
  2. 模板的特化版本和模板的泛化版本都应该放在同一个.h中
  3. .h文件前面放泛化,后边放特化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值