模板为什么要特化,因为编译器认为,对于特定的类型,如果你能对某一功能更好的实现,那么就该听你的。
模板分为类模板与函数模板,特化分为全特化与偏特化。全特化就是限定死模板实现的具体类型,偏特化就是如果这个模板有多个类型,那么只限定其中的一部分。
先看类模板:
那么下面3句依次调用类模板、全特化与偏特化:
而对于函数模板,却只有全特化,不能偏特化:
备注:
1 函数不能偏特化:
因为函数(以及函数模板)本身具有偏序的重载决议(overload resolution),因此偏特化就被否决了。你完全可以分别定义
template <typename T> void fun(T)
template <typename T> void fun(T*)
来起到和偏特化同样的目的。
当然,这个规定阻止你写:
template <typename T> void fun()
template <typename T> void fun<T*>()
这暗示着函数模板参数应该被尽量用于函数参数,因为这是函数模板参数的根本用途所在。
如果一定需要如上的应用,可以将它们定义成(带公有函数的,特别是可以重载operator()的)类模版,用类模版的偏特化来实现;此时,就无法使用(也不需要使用)函数模板之间的重载决议了。
(1) 普通函数,如果类型匹配,优先选中,重载解析结束;
(2) 如果没有普通函数匹配,那么所有的基础函数模版进入候选,编译器开始平等挑选,类型最匹配的,则被选中,注意,此时才会进入第(3)步继续筛选;
(3) 如果第(2)步里面选中了一个模版基础函数,则查找这个模版基础函数是否有全特化版本,如果有且类型匹配,则选中全特化版本,重载解析结束,否则使用(2)里面选中的模版函数,重载解析依然结束。
(4) 如果第(2)步里面没有选中任何函数基础模版,那么匹配失败,编译器会报错,程序员需要检查下代码。
3 尽量不要全特化:
函数模版的全特化版本不参与函数重载解析,并且优先级低于函数基础模版参与匹配的原因是:C++标准委员会认为如果因为程序员随意写了一个函数模版的全特化版本,而使得原先的重载函数模板匹配结果发生改变(也就是改变了约定的重载解析规则)是不能接受的。函数模版的全特化到底是哪个函数基础模版的特化,需要参考可见原则,也就是说当特化版本声明时,它只可能特化的是当前编译单元已经定义的函数基础模版。
鉴于上面两个原因,为何还要进行函数模版全特化把自己搞晕呢?!因为函数的全特化的版本和定义一个普通函数基本上一样,把模版声明去掉即可,而且普通函数的重载优先级最高,也就不会踩一些坑了。
本文转自:
http://blog.csdn.net/s983134950/article/details/45167723
http://blog.csdn.net/magictong/article/details/48573737