模板的特化

举报
跳动的bit 发表于 2022/08/30 07:32:21 2022/08/30
【摘要】 一、模板的特化 💦 概念通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型可能会得到一些错误的结果,比如:template<class T>bool IsEqual(const T& left, const T& right){ //C/C++不支持用类型比较 /*if(T == const char*)//string {} else//int {}*/ retur...

一、模板的特化

💦 概念

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型可能会得到一些错误的结果,比如:

template<class T>
bool IsEqual(const T& left, const T& right)
{
	//C/C++不支持用类型比较
	/*if(T == const char*)//string
	{}
	else//int
	{}*/
	
	return left == right;
}
int main()
{
	cout << IsEqual(1, 2) << endl;//ok

	char p1[] = "hello";
	char p2[] = "hello";
	cout << IsEqual(p1, p2) << endl;//err

	return 0; 
}

📝说明

可以看到对于 IsEqual 函数,它支持用 2 个整型去比较,但是它不支持字符串比较,且这里的 p1 and p2 比的是地址。大聪明们一般会判断类型,但是在 C/C++ 中不可以使用类型去比较,所以 C/C++ 里针对这种场景给出了 " 模板特化 " —— 在原模板类的基础上,针对某些类型进行特殊化处理。模板特化又分为函数模板特化和类模板特化。

💦 函数模板特化

函数模板的特化步骤:

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

//函数模板匹配原则
//err,表达式必须是可修改的左值,p1 and p2做为形参传给left and right,并且是p1 and p2的别名,这里 p1 and p2 是数组名,带有const属性,注意实参的const修饰的是*left,这里属于权限放大。
//bool IsEqual(const char*& left, const char*& right)
/*bool IsEqual(const char* const& left, const char* const& right)//ok,这里就非常考验咱基础扎实与否了,const在*左边,修饰*left,const在*右边,修饰left。
{
	return strcmp(left, right) == 0;
}*/
//同上,不使用引用就可以不用const,因为这时是值拷贝,并不会影响实参。
/*bool IsEqual(const char* left, const char* right)
{
	return strcmp(left, right) == 0;
}*/

//函数模板的特化,有bug,待改
template<>
bool IsEqual<const char*>(const char* const& left, const char* const& right)

{
	return strcmp(left, right) == 0;
}
int main()
{
	cout << IsEqual(1, 2) << endl;//ok

	char p1[] = "hello";
	char p2[] = "hello";
	cout << IsEqual(p1, p2) << endl;

	return 0; 
}

📝说明

严格的说,以上 2 种写法不是特化,而是模板的匹配原则 —— a) 有现成完全匹配的,就直接调用,没有现成调用的,实例化模板生成。 b) 有需要转换匹配的,那么它会优先选择去实例化模板生成。

再来看一个例子:

template<class T>
void Swap(T& a, T& b)
{
	//对于v1 and v2对象虽然Swap能成功,但是Swap里会完成3次深拷贝,所以针对v1 and v2我们有必要做特殊处理。
	T tmp = a;
	a = b;
	b = tmp;
}
//模板匹配原则来进行特殊处理
/*void Swap(vector<int>& a, vector<int>& b)
{
	a.swap(b);
}*/
//函数模板的特化,标准的特殊化处理
template<>
void Swap<vector<int>>(vector<int>& a, vector<int>& b)
{
	a.swap(b);
}
//对于下面的v3 and v4,目前好像只能这样特化
template<>
void Swap<vector<double>>(vector<double>& a, vector<double>& b)
{
	a.swap(b);
}
int main()
{
	int x = 1, y = 2;
	Swap(x, y);
	
	vector<int> v1 = { 1, 2, 3, 4 };
	vector<int> v2 = { 10, 20, 30 };
	Swap(v1, v2);

	vector<double> v3 = { 1.1, 2.2, 3.3, 4.4 };
	vector<double> v4 = { 10.1, 20.2, 30.3 };
	Swap(v3, v4);
	
	return 0;
}

📝说明

对于模板匹配原则 and 函数模板特化,两者底层并无差别,如果能使用模板匹配原则特化就更推荐使用模板匹配原则来进行特化。

💦 类模板特化

1、全特化

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

template<class T1, class T2>
class Data
{
public:
	Data(){cout << "Data<T1, T2>" << endl;}
private:
	T1 _d1;
	T2 _d2;
};
//全特化
template<>
class Data<double, double>
{
public:
	Data(){cout << "Data<double, double>" << endl;}
private:
};
int main()
{
	Data<int, int> d1;
	Data<double, double> d2;
	return 0;
}
2、偏特化

偏特化 (半特化):任何针对模版参数进一步进行条件限制设计的特化版本。比如对于以下模板类:

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

//偏特化(半特化)
//只要第二个模板参数是char,那么它就会匹配
template<class T1>
class Data<T1, char>
{
public:
	Data(){cout << "Data<T1, char>" << endl;}
private:
	T1 _d1;
};

//当两个模板参数是指针就会匹配,不管是什么类型的指针
template<class T1, class T2>
class Data<T1*, T2*>
{
public:
	Data(){cout << "Data<T1*, T2*>" << endl;}
private:
	T1 _d1;
	T2 _d2;
};
//T1&, T2&
template<class T1, class T2>
class Data<T1&, T2&>
{
public:
	Data(){cout << "Data<T1&, T2&>" << endl;}
private:
	T1 _d1;
	T2 _d2;
};
//T1&, T2*
template<class T1, class T2>
class Data<T1&, T2*>
{
public:
	Data(){cout << "Data<T1&, T2*>" << endl;}
private:
	T1 _d1;
	T2 _d2;
};
int main()
{
	Data<double, int> d1;
	Data<double, char> d2;
	Data<int*, char*> d3;
	Data<int&, char&> d4;
	Data<int&, char*> d5;

	return 0;
}

📝说明

偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本,比如说限定你的类型是指针。

在前面谈到的类型萃取本质就是特化,关于特化的场景我们现在还不好举例,等后面的哈希表会再见面。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。