首先,特化是什么?
之前实现vector时,我们发现传参传string时,拷贝构造与扩容不应该用简单的浅拷贝,而是应该调用赋值实现。但是对于int,char这种内置类型又可以直接使用值拷贝,显然我们不能在同一份代码里对于不同类型实现两个方法。
也就说明,当一个模板类不能适用于所有类型时,我们可以单拉出来一个特化出来的类,当我们需要这个类的时候编译器会去找这个被特化的类。
全特化
比如上面那个例子:我们可以将某一个类拎出来特化。
通俗点说,全特化,就是限定死这个模板的类型
还是用vector来说明:
template<class T>
class Vector
{
public:
Vector()
{
cout<<"class T Vector()"<<endl;
}
protected:
size_t size;
size_t capacity;
T* data;
};
template<>
class Vector<int>//全特化
{
public:
Vector()
{
cout<<"class int Vector()"<<endl;
}
protected:
size_t size;
size_t capacity;
int* data;
};
int main()
{
Vector<int> v1;
Vector<double> v2;
return 0;
}
结果:
偏特化
偏特化是指在不止有一个类型时,我只特化其中一种或多种类型。
比如下面这个:
template <class T1,class T2>
class Date
{
public:
Date()
{
cout<<"Date(T1,T2)"<<endl;
}
private:
T1 t1;
T2 t2;
};
template <class T1>
class Date<T1,int>//偏特化
{
public:
Date()
{
cout<<"Date(T1,int)"<<endl;
}
private:
T1 t1;
int t2;
};
该模板有两个类型,特化其中一个类型为int,那么在实例化的时候,只要第二个参数是int类型的,都会去调用这个特化后的模板。
可以看到,
特化可以说是对参数类型做出一些要求,比如下面的例子也是可以的
template <class T1,class T2>
class <T1*,T2*>
template <class T1,class T2>
class <T1&,T2&>
偏特化不仅仅是指对参数的一部分进行特化,而是对参数做出一些要求。
类型萃取
还是在实现vector的时候,我们遇到了对于不同类型实现拷贝方式的方式不同。
比如:对于int,char使用memcpy就已经可以实现了,当然使用operator=也是没问题的,但是显然效率前者会高那么一些。
但是对于,string这种对象,或是与深浅拷贝有关的自定义类型,使用memcpy就会出现问题,使用operator=赋值就更加合适,避免出现深浅拷贝时出现的问题。
那么我有没有一种方法能够在同一个类中实现对不同类型去执行不同的方法,比如上例中的,如果是int,char等我就去执行memcpy方法,如果是string就去执行operator=。
c++提供了类型萃取,可以实现这种功能
下面从代码的角度来叙述
第一步:定义类型,区分内置类型与自定义类型
struct _TrueType//是无关紧要的类型,即内置类型
{};
struct _FalseType//不是无关紧要的类型,即自定义类型
{};
第二步:
特化需要特化的类型,自定义类型显然无穷无尽,我们特化不完,所以我们可以把有限的内置类型特化完全。
template <class T>
struct TypeTraits
{
typedef _FalseType IsPodType; //自定义类型,不是无关痛痒的类型
};
//以下特化内置类型
template<>
struct TypeTraits<int>
{
typedef _TrueType IsPodType;//是无关痛痒的类型吗?是的
};
template<>
struct TypeTraits<char>
{
typedef _TrueType IsPodType;//是无关痛痒的类型吗?是的
};
template<>
struct TypeTraits<double>
{
typedef _TrueType IsPodType;//是无关痛痒的类型吗?是的
};
接下来,重载拷贝函数,针对自定义类型与内置类型分别给出两种不同的方法,以TrueType,FalseType区分:
template<class T>
void __TypeCopy(T* dst,const T* src,size_t size,_TrueType)
{
cout<<"__TrueType"<<endl;
memcpy(dst,src,size);
}
template<class T>
void __TypeCopy(T* dst,const T* src,size_t size,_FalseType)
{
cout<<"__FalseType"<<endl;
for(size_t i=0;i<size;i++)
{
dst[i]=src[i];
}
}
调用函数:取出IsPODType,判断是否为无关痛痒的类型,也就是判断你到底是TrueType还是FalseType,然后根据你是什么类型去调你自己的方法。
template<class T>
void TypeCopy(T* dst,const T* src,size_t size)
{
__TypeCopy(dst,src,size,TypeTraits<T>::IsPodType());
};
结果如下: