C++模板的特化与偏特化
最近在看STL的过程中,发现自己对于模板这里的知识有所生疏,因此今日将这部分内容再做整理,以备后忘。
关于C++模板的概念这里不再赘述,默认读者已经具备基础知识。
模板的特化
先看一段代码:
#include <iostream>
using namespace std;
template <class T>
class TClass
{
public:
bool Equal(const T& arg, const T& arg1);
};
template <class T>
bool TClass<T>::Equal(const T& arg, const T& arg1)
{
return (arg == arg1);
}
int main()
{
TClass<int> obj;
cout<<obj.Equal(2, 2)<<endl;
cout<<obj.Equal(2, 4)<<endl;
}类里面就包括一个Equal方法,用来比较两个参数是否相等;上面的代码运行没有任何问题;但是,如果你传入一个float和一个double类型的参数,那么得到的结果有可能不是你想要的。所以,对于float或者double类型,我们需要进行特殊处理,处理如下:
#include <iostream>
using namespace std;
template <class T>
class Compare
{
public:
bool IsEqual(const T& arg, const T& arg1);
};
// 已经不具有template的意思了,已经明确为float了
template <>
class Compare<float>
{
public:
bool IsEqual(const float& arg, const float& arg1);
};
// 已经不具有template的意思了,已经明确为double了
template <>
class Compare<double>
{
public:
bool IsEqual(const double& arg, const double& arg1);
};
template <class T>
bool Compare<T>::IsEqual(const T& arg, const T& arg1)
{
cout<<"Call Compare<T>::IsEqual"<<endl;
return (arg == arg1);
}
bool Compare<float>::IsEqual(const float& arg, const float& arg1)
{
cout<<"Call Compare<float>::IsEqual"<<endl;
return (abs(arg - arg1) < 10e-3);
}
bool Compare<double>::IsEqual(const double& arg, const double& arg1)
{
cout<<"Call Compare<double>::IsEqual"<<endl;
return (abs(arg - arg1) < 10e-6);
}
int main()
{
Compare<int> obj;
Compare<float> obj1;
Compare<double> obj2;
cout<<obj.IsEqual(2, 2)<<endl;
cout<<obj1.IsEqual(2.003, 2.002)<<endl;
cout<<obj2.IsEqual(3.000002, 3.0000021)<<endl;
}这样就实现了模板的特化,对于float和double的特化版本,甚至可以做一些与非特化的不一样的事情,这也是模板特化的初衷,使得特化的模板具有与非特化模板一同的行为。
模板偏特化
上面对模板的特化进行了总结。那模板的偏特化呢?所谓的偏特化是指提供另一份template定义式,而其本身仍为templatized;也就是说,针对template参数更进一步的条件限制所设计出来的一个特化版本。这种偏特化的应用在STL中是随处可见的。比如:
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;
};
template <class T>
struct iterator_traits<T*> {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
template <class T>
struct iterator_traits<const T*> {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
};模板的偏特化与模板特化的区别在于,模板特化以后,实际上其本身已经不是templatized,而偏特化,仍然带有templatized。我们来看一个实际的例子:
#include <iostream>
using namespace std;
// 一般化设计
template <class T1, class T2>
class TestClass
{
public:
TestClass()
{
cout << "T1, T2" << endl;
}
};
// 针对普通指针的偏特化设计
template <class T1, class T2>
class TestClass<T1*, T2*>
{
public:
TestClass()
{
cout << "T1*, T2*" << endl;
}
};
// 针对const指针的偏特化设计
template <class T1, class T2>
class TestClass<const T1*, T2*>
{
public:
TestClass()
{
cout << "const T1*, T2*" << endl;
}
};
int main()
{
TestClass<int, char> obj; //T1,T2
TestClass<int *, char *> obj1; //T1*,T2*
TestClass<const int *, char *> obj2; //const T1*,T2*
return 0;
}上面的代码就实现了模板的偏特化
特化与偏特化的调用顺序
对于模板、模板的特化和模板的偏特化都存在的情况下,编译器在编译阶段进行匹配时,是如何抉择的呢?从哲学的角度来说,应该先照顾最特殊的,然后才是次特殊的,最后才是最普通的。编译器进行抉择也是尊从的这个道理。从上面的例子中,我们也可以看的出来,这就就不再举例说明。
本文出自 “11408774” 博客,请务必保留此出处http://11418774.blog.51cto.com/11408774/1794683
原文:http://11418774.blog.51cto.com/11408774/1794683