有时需要对模板进行特化。即在原模板类的基础上,针对特殊类型所进行特殊化的实现方式。
模板特化中分为函数模板特化与类模板特化
比如:
下面这个例子当IsEqual()参数为整形或者浮点时都能判断两变量是否相等。
但是当两参数为字符串时,比较量字符串是否相同需常用strcmp(left, right)来判断,而不是用 == 来判断地址是否相同。
这就需要针对此模板做出一个针对字符串参数特殊化处理的模板。
template<class T>
bool IsEqual(T& left, T& right)
{
return left == right;
}
void Test()
{
char* p1 = "hello";
char* p2 = "world";
if(IsEqual(p1, p2))
cout<<“==”<<endl;
else
cout<<“!=”<<endl;
}
函数模板的特化规则:
以下是针对上面问题中字符串指针的特殊化处理示例:
template<>
bool IsEqual<char*>(char*& left, char*& right)
{
if(strcmp(left, right) > 0)
return true;
return false;
}
一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给出。如:
bool IsEqual(char* left, char* right)
{
if(strcmp(left, right) > 0)
return true;
return false;
}
全特化即是将模板参数列表中所有的参数都确定化。
与函数模板的特化规则相似
template<class T1, class T2>
class Data
{
public:
Data() {cout<<"Data" <<endl;}
private:
T1 _d1;
T2 _d2;
};
//全特化
template<>
class Data<int, char>
{
public:
Data() {cout<<"Data" <<endl;}
private:
T1 _d1;
T2 _d2;
};
void TestVector()
{
Data<int, int> d1;
Data<int, char> d2;
}
偏特化也就是只特化了一部分参数。
eg:
template<class T1, class T2>
class Data
{
public:
Data() {cout<<"Data" <<endl;}
private:
T1 _d1;
T2 _d2;
};
// 将第二个参数特化为int
template <class T1>
class Data<T1, int>
{
public:
Data() {cout<<"Data" <<endl;}
private:
T1 _d1;
int _d2;
};
//两个参数偏特化为指针类型
template <typename T1, typename T2>
class Data <T1*, T2*>
{
public:
Data() {cout<<"Data" <<endl;}
private:
T1 _d1;
T2 _d2;
};
//两个参数偏特化为引用类型
template <typename T1, typename T2>
class Data <T1&, T2&>
{
public:
Data(const T1& d1, const T2& d2): _d1(d1), _d2(d2)
{
cout<<"Data" <<endl;
}
private:
const T1 & _d1;
const T2 & _d2;
};
void test2 ()
{
Data<double , int> d1; // 调用特化的int版本
Data<int , double> d2; // 调用基础的模板
Data<int *, int*> d3; // 调用特化的指针版本
Data<int&, int&> d4(1, 2); // 调用特化的指针版本
}
类型萃取是类模板特化的一种应用。
作用:通过类型萃取,萃取到变量类型,对不同变量进行不同处理,可以提升程序效率.
可以通过下面例子理解。
其中GetSum()函数是一个统一的接口,传入对象和一个数值 用来获取不同类型值(int/float)通过计算得到的值。
要求输入对象为IntArray则GetSum()的另一个参数和计算结果都为int类型,输入对象为FloatArray则GetSum()的另一个参数和计算结果都为float类型.
无论用int或float作为GetSum()函数的返回类型,都只能返回其中一种类型。这就需要用到萃取技术来萃取返回值的类型。
class IntArray
{
public:
IntArray()
{
for(int i=1; i<=10; ++i)
ar[i-1] = i;
}
int GetSum(int time)
{
int sum = 0;
for(int i=0; i<10; ++i)
sum += ar[i];
return sum *time;
}
private:
int ar[10];
};
class FloatArray
{
public:
FloatArray()
{
for(int i=0; i<10; ++i)
ar[i] = i + 1.11;
}
float GetSum(float time)
{
float sum = 0.0f;
for(int i=0; i<10; ++i)
sum += ar[i];
return sum *time;
}
private:
float ar[10];
};
///萃取/
template<class Type>
class NumTraits //基础类--空类
{};
template<>
class NumTraits<IntArray>
{
public:
typedef int return_type; //萃取返回值类型 ---》 int
typedef int arg_type; //萃取参数类型 ---》 int
};
template<>
class NumTraits<FloatArray>
{
public:
typedef float return_type;
typedef float arg_type;
};
template<class Type>
class CApply
{
public:
//通过萃取技术,这里根据传入的参数类型不同,返回值类型也不同。
typename NumTraits<Type>::return_type GetSum(Type &obj,typename NumTraits<Type>::arg_type time)
{ //typename NumTraits::return_type 告诉编译器typename后面的这堆东西为一个类型
//这里可将NumTraits::return_type看作int或者float
return obj.GetSum(time);
}
};
void main()
{
IntArray intA;
FloatArray floatA;
CApply<IntArray> obj;
cout<<obj.GetSum(intA,3)<<endl; //165
CApply<FloatArray> obj1;
cout<<obj1.GetSum(floatA,2.3)<<endl; //129.03
}