【C++】模板特化、偏特化

本文深入探讨C++中的模板特化概念,包括全特化和偏特化,通过实例解析函数模板和类模板的特化过程,以及特化在实际编程中的应用,如hash<float>和vector<bool>的特化案例。
摘要由CSDN通过智能技术生成

  模板分为函数模板类模板,特化分为全特化偏特化Partial Specialization)。其中,类模板有全特化和偏特化,函数模板只能全特化。使用模板的时候,我们的目的就是希望可以不用每个类型实现一遍,而是用一个模板代替这个类型。如果所有类型的实现都是一个统一的一样的实现,就不需要模板特化或者偏特化了,但是大多数情况是肯定有特殊版本需要特殊处理的,有两个典型例子:
1、hash<_Kty>:模板全特化
2、vector<bool>:模板偏特化

  文章分为 3 部分:
1、模板全特化(函数模板只能全特化
  1.1 类模板全特化
  1.2 函数模板全特化
2、模板偏特化
  2.1 个数上偏特化
  2.2 范围上偏特化
3、总结

一、模板全特化
1.1 类模板全特化

  C++11中新加入的容器 unordered_setunordered_map 以及他们的 multi 版本,底层都是哈希表,模板参数如下:

template<class _Kty,
		 class _Hasher = hash<_Kty>,
		 class _Keyeq  = equal_to<_Kty>,
		 class _Alloc  = allocator<_Kty>>

  可以看到第一个参数就是我们要填入的 unordered_set 要存放的元素的类型,第二个参数就是 hash 函数,默认使用 hash<_Kty>,我们跳到 hash<_Kty> 实现部分可以看到:

  除了模板形式的 hash<_Kty>,还有很多特化版本,比如 hash<float>。模板版本就是 template<class _Kty>

template<class _Kty>
struct hash	: __blalbla	// 一大堆,省略掉先
{
	// hash functor primary template (handles enums, integrals, and pointers)
	static size_t _Do_hash(const _Kty& _Keyval) noexcept {
		// hash _Keyval to size_t value by pseudorandomizing transform
		return (_Hash_representation(_Keyval));
	}
};

  而特化版本,则是在类前边加上 template<>告诉编译器,下边这个是特化版本,而且后边写的时候要明确写出 struct hash<float>,告诉编译器特化的版本的模板类型:

template<>
struct hash<float>
{
	// hash functor for float
	_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef float argument_type;
	_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t result_type;
	_NODISCARD size_t operator()(const float _Keyval) const noexcept {
		// hash _Keyval to size_t value by pseudorandomizing transform
		return (_Hash_representation(_Keyval == 0.0F ? 0.0F : _Keyval));	// map -0 to 0
	}
};
1.2 函数模板全特化

  C++不允许函数模板偏特化,可能是因为函数可以直接重载?

//模板函数  
template<typename T1, typename T2>
void fun(T1 a, T2 b) {
	cout << "模板函数" << endl;
}

//全特化  
template<>
void fun<int, char >(int a, char b) {
	cout << "全特化" << endl;
}
二、模板偏特化 Partial Specialization

  模板偏特化是指模板列表中一部分特化,一部分不特化,比如 vector<bool>。我们知道 vector<bool> 和其他的 vector 不一样,他使用一个 bit 来存储一个元素,因为只有 truefalseC++ STL 里边所有容器,只有 vector 对 bool 进行了这样的特化)。
  模板偏特化分为:范围上偏特化,个数上偏特化

2.1 个数上偏特化

  正常的 vector 如下(比如一个 vector<int> vi;,我们跳过去):

// CLASS TEMPLATE vector
template<class _Ty, class _Alloc = allocator<_Ty>>
class vector // : blabla // 继承这里不关心,省略掉
{
	// varying size array of values
	// ...
}

  正常的如 vector<int> vi; 是有两个模板参数的,第一个是元素类型,第二个是存储方式,默认是 allocator<_Ty>,我们在声明一个 vector<bool> vb;,跳过去看:

// CLASS vector<bool>
template<class _Alloc>
class vector<bool, _Alloc> : public _Vb_val<_Alloc>
{
	// varying size array of bits
	// ...
}

  类前边只写了一个模板 template<class _Alloc>,而在下边写明了 class vector<bool, _Alloc>,这样编译器就知道是偏特化了。这种模板参数个数变化的,就是个数上的偏特化。

2.1 范围上偏特化

  下边这样,模板参数个数没有变化,而是从值变成指针,就是范围上偏特化。

template<typename T>
class C
{
	
};

template<typename T>
class C<T*>
{

};

int main() {
	C<int> c;
	C<int*> cp;
}
三、总结
  • 为什么要特化:
      如果对于一个模板功能,或者模板类,如果对于特定类型有更好的、更合适的或者有特殊需求的实现,就应该提供特化版本,让编译器知道;
  • 模板优先级
      没有特化的版本,就叫 模板泛化(优先级:全特化 > 偏特化 > 泛化),所以才能针对特定类型进行特定实现;
  • 想到新的再写。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值