C++模板的特化
By SmartPtr(http://www.cppblog.com/SmartPtr/)
模板特化不同于模板的实例化,模板参数在某种特定类型下的具体实现称为模板的特化,以实现特定类型下非通用行为。模板特化有时也称之为模板的具体化,分别有函数模板特化和类模板特化。
针对一个模板参数的类模板特化的几种类型, 一是特化为绝对类型(全特化); 二是特化为引用,指针类型(半特化、偏特化);三是特化为另外一个类模板(复杂点的偏特化)。
用一个简单的例子来说明这三种:
// general version template<class T> class Compare { public: static bool IsEqual(const T& lh, const T& rh) { return lh == rh; } };
这是一个用于比较的类模板,里面可以有多种用于比较的函数, 以IsEqual为例。
一、特化为绝对类型
也就是说直接为某个特定类型做特化,这是我们最常见的一种特化方式,
如特化为float, double等
// specialize for float template<> class Compare<float> { public: static bool IsEqual(const float& lh, const float& rh) { return abs(lh - rh) < 10e-3; } }; // specialize for double template<> class Compare<double> { public: static bool IsEqual(const double& lh, const double& rh) { return abs(lh - rh) < 10e-6; } };
二、特化为引用,指针类型
这种特化我最初是在stl源码的的iterator_traits特化中发现的, 如下:
template <class _Iterator> struct iterator_traits { typedef typename _Iterator::iterator_category iterator_category; typedef typename _Iterator::value_type value_type; typedef typename _Iterator::difference_type difference_type; typedef typename _Iterator::pointer pointer; typedef typename _Iterator::reference reference; }; // specialize for _Tp* template <class _Tp> struct iterator_traits<_Tp*> { typedef random_access_iterator_tag iterator_category; typedef _Tp value_type; typedef ptrdiff_t difference_type; typedef _Tp* pointer; typedef _Tp& reference; }; // specialize for const _Tp* template <class _Tp> struct iterator_traits<const _Tp*> { typedef random_access_iterator_tag iterator_category; typedef _Tp value_type; typedef ptrdiff_t difference_type; typedef const _Tp* pointer; typedef const _Tp& reference; };
当然,除了T*, 我们也可以将T特化为 const T*, T&, const T&等,以下还是以T*为例:
// specialize for T* template<class T> class Compare<T*> { public: static bool IsEqual(const T* lh, const T* rh) { return Compare<T>::IsEqual(*lh, *rh); } };
这种特化其实是就不是一种绝对的特化, 它只是对类型做了某些限定,但仍然保留了其一定的模板性,这种特化给我们提供了极大的方便, 如这里, 我们就不需要对int*, float*, double*等等类型分别做特化了。
三、特化为另外一个类模板
这其实是第二种方式的扩展,其实也是对类型做了某种限定,而不是绝对化为某个具体类型,如下:
// specialize for vector<T> template<class T> class Compare<vector<T> > { public: static bool IsEqual(const vector<T>& lh, const vector<T>& rh) { if(lh.size() != rh.size()) return false; else { for(int i = 0; i < lh.size(); ++i) { if(lh[i] != rh[i]) return false; } } return true; } };
这就把IsEqual的参数限定为一种vector类型, 但具体是vector<int>还是vector<float>, 我们可以不关心, 因为对于这两种类型,我们的处理方式是一样的,我们可以把这种方式称为“半特化”。
当然, 我们可以将其“半特化”为任何我们自定义的模板类类型:
// specialize for any template class type template <class T1> struct SpecializedType { T1 x1; T1 x2; }; template <class T> class Compare<SpecializedType<T> > { public: static bool IsEqual(const SpecializedType<T>& lh, const SpecializedType<T>& rh) { return Compare<T>::IsEqual(lh.x1 + lh.x2, rh.x1 + rh.x2); } };
这就是三种类型的模板特化, 我们可以这么使用这个Compare类:
// int int i1 = 10; int i2 = 10; bool r1 = Compare<int>::IsEqual(i1, i2); // float float f1 = 10; float f2 = 10; bool r2 = Compare<float>::IsEqual(f1, f2); // double double d1 = 10; double d2 = 10; bool r3 = Compare<double>::IsEqual(d1, d2); // pointer int* p1 = &i1; int* p2 = &i2; bool r4 = Compare<int*>::IsEqual(p1, p2); // vector<T> vector<int> v1; v1.push_back(1); v1.push_back(2); vector<int> v2; v2.push_back(1); v2.push_back(2); bool r5 = Compare<vector<int> >::IsEqual(v1, v2); // custom template class SpecializedType<float> s1 = {10.1f,10.2f}; SpecializedType<float> s2 = {10.3f,10.0f}; bool r6 = Compare<SpecializedType<float> >::IsEqual(s1, s2);
C++模板编程中只特化模板类的一个成员函数(花样特化一个成员函数)的方法
C++函数模板的特化
函数模板的特化,函数模板只有全特化,没有半特化
看下面的例子
main() { int highest = mymax(5,10); char c = mymax(‘a’, ’z’); const char* p1 = “hello”; const char* p2 = “world”; const char* p = mymax(p1,p2); }
前面两个mymax都能返回正确的结果.而第三个却不能,因为,此时mymax直接比较两个指针p1 和 p2 而不是其指向的内容.
针对这种情况,当mymax函数的参数类型为const char* 时,需要特化。
template <class T> T mymax(const T t1, const T t2) { return t1 < t2 ? t2 : t1; } template <> const char* mymax(const char* t1,const char* t2) { return (strcmp(t1,t2) < 0) ? t2 : t1; }
现在mymax(p1,p2)能够返回正确的结果了
函数模板的偏特化
严格的来说,函数模板并不支持偏特化,但由于可以对函数进行重载,所以可以达到类似于类模板偏特化的效果。
template <class T> void f(T); (a)
根据重载规则,对(a)进行重载
template < class T> void f(T*); (b)
如果将(a)称为基模板,那么(b)称为对基模板(a)的重载,而非对(a)的偏特化。
C++的标准委员会仍在对下一个版本中是否允许函数模板的偏特化进行讨论。