template之全特化和偏特化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Function_Dou/article/details/84783953

前言

关于讲过traits萃取器的时候探讨到偏特化的概念, 而在那一篇文章也没有具体解释偏特化是什么, 怎么实现, 所以可能在第一次看得时候会很莫名其妙. 所以我将偏特化放在其后讲解, 为不明白的朋友做一个浅析的讲解. 这里我先聊一下全特化再聊偏特化.

全特化

全特化的模板参数列表应该是为空, 函数和类都可以实现全特化.

template<class T>
void fun(T a)
{
	cout << "fun a = " << a << endl;
}

template<>
void fun(int a)
{
	cout << "fun1 a = " << a << endl;
}

int main()
{
	fun(3.3);
	fun(3);

	exit(0);
}

结果如下

在这里插入图片描述

这就是函数全特化, 根据传入的参数让编译器自动推导参数的类型来调用其特殊的函数.

记住:

  1. 函数的全特化不是重载, 不是重载.
  2. 全特化的参数列表要为空, 为空
  3. 第二点成立是因为我们要实现一个相同的模板, 一个相同的模板

同样, 类的全特化也是一样的, 只要满足上面的三点就行了.

偏特化

函数不能偏特化, 类可以偏特化.

偏特化需要在运行实例化的时候才能推导确定使用哪一个模板类. 偏特化也是以template来声明的,需要给出剩余的”模板形参”和必要的”模板实参”.

template<class T>
class Point
{
	public:
		void Print()
		{
			cout << "Point" << endl;
		}
};
template<class T>
class Point<const T>
{
	public:
		void Print()
		{
			cout << "const Point" << endl;
		}
};
int main()
{
	Point<double> b;
	b.Print();
	Point<const int> c;
	c.Print();

	exit(0);
}

以上就实现了一个关于const T的偏特化, 这就很像traits萃取器实现的偏特化了.
在这里插入图片描述

偏特化的重点 :

  1. 函数不能偏特化, 因为函数可以重载, 也就可以实现类型偏特化一样的功, 而类不可以重载.
  2. 偏特化只是针对一些特殊的参数类型.
  3. 偏特化实现了类的"重载".

还有除了可以特化类模板之外, 还可以对类模板中的成员函数和普通静态成员变量进行特化.

优先级

上面全特化和偏特化还有一点没有谈论到, 关于优先级. 现在我们就来看一下

// 这是上面的一个实例
fun(3.3);
fun(3);

fun(3)的函数不是调用template<class T> void fun(T a)而优先调用的是<int>的全特化模板.

同样偏特化的的例子也能证明这一点

Point<double> b;
b.Print();
Point<const int> c;
c.Print();

类优先调用了最合适的模板.

上面就可以归纳为:

  1. 全特化/偏特化, 普通模板(优先级从左到右依次减小)

现在我们再实现一个普通没有模板的fun函数

void fun(int a) {}

如果继续调用fun(3), 你会发现此时没有任何输出. 那是不是没有实现的模板函数和类的实例会优先被调用呢? 确实如此.

以上就可以归纳为 :

  1. 全特化/偏特化, 普通模板(优先级从左到右依次减小)
  2. 无模板函数优先级最高

总结

函数只能全特化, 不能偏特化, 类既可以全特化, 也可以偏特化. 函数不能偏特化但是可以重载, 类不能进行重载.

优先级 : 无模板函数 > 全特化/偏特化 > 普通模板

现在如果重新去看traits萃取器应该就能理解traits编程使用偏特化的意义.

猜你喜欢

转载自blog.csdn.net/Function_Dou/article/details/84783953
今日推荐