一、类型萃取(类模板特化应用)
Q:如何实现一个通用的拷贝函数?
1.使用memcpy函数
template<class T>
void Copy(T* dst,const T* src,size_t size)
{
memcpy(dst,src,sizeof(T)*size);
}
上面实现虽然任意类型的空间都可以拷贝,但是自定义类型有可能涉及到深拷贝,而memcpy是浅拷贝,可能会出错。如果对象中涉及到资源管理,就只能用赋值。
2.使用赋值方式拷贝
template<class T>
void Copy(T* dst,const T*src,size_t size)
{
for(size_t i=0;i<size;++i)
{
dst[i]=src[i];
}
}
用循环赋值的方式可以实现,但是效率很低。
因此考虑实现遇到内置类型用memcpy拷贝,遇到自定义类型用循环方式来做
3.增加bool类型区分自定义与内置类型
template<class T>
void Copy(T* dst,const T* src,size_t size,bool IsPodType)
{
if(IsPodType)
memcpy(dst,src,sizeof(T)*size);
else
{
for(size_t i=0;i<size;++i)
dst[i]=src[i];
}
}
通过多传递一个参数,可将上面两种拷贝的优势结合起来。但是缺陷是:用户要根据所拷贝元素的类型去传递参数,会有出错的可能。所以我们考虑是否能够让函数自动识别是哪种类型。
4.使用函数区分内置与自定义类型
//Pod:代表基本类型
//此处举例,只列出部分类型
bool IsPodType(const char* strType)
{
const char* arrType[]={"char","short","int","long","float"};
for(size_t i=0;i<sizeof(arrType)/sizeof(arrType[0]);++i)
{
if(0==strcmp(strType,arrType[i])
return true;
}
return false;
}
template<class T>
void Copy(T* dst,T* src,size_t size)
{
if(IsPodType(typeid(T).name())
memcpy(dst,src,sizeof(T)*size);
else
{
for(size_t i=0;i<size;++i)
dst[i]=src[i];
}
}
通过typeid确认实际类型,再在内置类型集合中枚举是否出现过,就可以确认所拷贝元素的类型。但缺陷是:枚举要将所有类型遍历一遍,效率较低。
5.类型萃取
为了区分内置类型与自定义类型,给出下面两个类代表自定义类型和内置类型
//内置类型
struct TrueType
{
static bool Get()
{
return true;
}
};
//自定义类型
struct FalseType
{
static bool Get()
{
return false;
}
};
给出以下类模板,之后可以对任何类型进行实例化
template<class T>
struct Type
{
typedef FalseType IsPodType;
};
对上面的类模板进行实例化
template <>
struct Type<char>
{
typedef TrueType IsPodType;
};
template<>
struct Type<short>
{
typedef TrueType IsPodType;
};
template<>
struct Type<int>
{
typedef TrueType IsPodType;
};
//对所有的内置类型都进行特化
通过对Type类模板的重写改写,来确认所拷贝对象的实际类型
//如果T为int类型,程序运行就会使用特化过的Type<int>,该类中的IsPodType是类TrueType,TrueType中Get函数返回true,实现内置类型用memcpy方式拷贝
//如果T为string类型,程序使用Type模板,该类模板中的IsPodType是FalseType,FalseType中Get函数返回false,实现自定义类型用赋值方式拷贝
template<class T>
void Copy(T* dst,T* src,size_t size)
{
if(Type<T>::IsPodType::Get())
memcpy(dst,src,sizeof(T)*size);
else
{
for(size_t i=0;i<size;++i)
dst[i]=src[i];
}
}