一、模板特化
在原模板的基础上对特殊类型进行特殊化。分为函数模板特化和类模板特化。
二、函数模板特化
特化步骤:
(前提要有一个基础的函数模板)
//1.template后加<> 2.函数名后加<指定type&> 3.形参表要和基础类型一样
//基础模板
template<class T>
bool IsEqual(T& left, T& right)
{
return left == right;
}
void Test1()
{
const char* p1 = "hello";
const char* p2 = "world";
if (IsEqual(p1, p2))
cout << p1 << endl;
else
cout << p2 << endl;
}
//特化
template<>
bool IsEqual<char*>(char*& left, char*& right)
{
if (strcmp(left, right) > 0)
return true;
return false;
}
三、类模板特化
1.分为全特化和偏特化
2.全特化:将模板参数类表中的参数类型都确定化。
template<typename T1,typename T2>
class Data
{
public:
Data()
{
cout << "Data<T1,T2> "<< endl;
}
private:
T1 _data1;
T2 _data2;
};
template<>
class Data<char,int>
{
public:
Data()
{
cout << "Data<char,int> " << endl;
}
private:
char _data1;
int _data2;
};
void Test()
{
Data<int, int> d1;
Data<char, int> d2;//调特化
}
2.偏特化
1>部分参数特化
template<typename T1, typename T2>
class Data
{
public:
Data()
{
cout << "Data<T1,T2> " << endl;
}
private:
T1 _data1;
T2 _data2;
};
//第二个参数特化为int
template<typename T1>
class Data<T1,int>
{
public:
Data()
{
cout << "Data<T1,int>" << endl;
}
private:
T1 _data1;
int _data2;
};
2>参数进一步限制:特化为指针,引用
//特化为指针
template<typename T1, typename T2>
class Data<T1* , T2*>
{
public:
Data()
{
cout << "Data<T1*,T2*> " << endl;
}
private:
T1 _data1;
T2 _data2;
};
//特化为引用
template<typename T1, typename T2>
class Data<T1& , T2&>
{
public:
Data(const T1& d1,const T2& d2)
:_data1(d1)
,_data2(d2)
{
cout << "Data<T1&,T2&> " << endl;
}
private:
const T1& _data1;
const T2& _data2;
};
调用时如果该类型特化过,就优先调用特化的模板。
四、类型萃取(重点)—实现拷贝函数
1.库函数提供了memcpy函数实现拷贝:是浅拷贝,拷贝自定义类型可能出错。
template<class T>
void Copy(T* dst, const T& src, size_t size)
{
memcpy(dst, src, sizeof(T)* size);
}
2.for循环一个一个拷贝:是深拷贝,但效率低。
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];
}
}
3.多传递一个参数ispod判断是不是内置类型,是的话就用浅拷贝,否则用深拷贝。但是这个参数需要用户手动传入,可能出错。
template<class T>
void Copy(T* dst, const T& src, size_t size, bool IsPOD)
{
if(IsPOD)
memcpy(dst, src, sizeof(T)*size);
else
{
for (size_t i = 0; i < size; i++)
dst[i] = src[i];
}
}
4.将所有内置类型全部枚举出来,通过typeid确定拷贝对象的实际类型,判断是否为内置类型。要在内置类型中比较,效率低。
bool IsPodType(const char* strType)
{
const char* arrType[] = { "char","short","int","long","long long","float","double","long double" };
for (size_t i = 0; i < sizeof(arrType) / sizeof(arrType[0]); i++)
{
if (strcmp(strType, arrType[i]))
return true;
return false;
}
}
template<class T>
void Copy(T* dst, const 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];
}
}
5.类型萃取:
//类型萃取:两个类区分内置类型和自定义类型
struct TrueType
{
static bool Get()
{
return true;
}
};
struct FalseType
{
static bool Get()
{
return false;
}
};
template<class T>
struct TypeTraits
{
typedef FalseType IsPOD;
};
template<>
struct TypeTraits<bool>
{
typedef TrueType IsPOD;
};
template<>
struct TypeTraits<int>
{
typedef TrueType IsPOD;
};
template<>
struct TypeTraits<char>
{
typedef TrueType IsPOD;
};
template<>
struct TypeTraits<short>
{
typedef TrueType IsPOD;
};
template<>
struct TypeTraits<double>
{
typedef TrueType IsPOD;
};
template<class T>
struct TypeTraits<T*>
{
typedef TrueType IsPOD;
};
//......
template<class T>
void Copy(T* dst, T* src, size_t size)
{
if(TypeTraits<T>::IsPOD::Get())
memcpy(dst, src, sizeof(T)*size);
else
{
for (size_t i = 0; i < size; i++)
dst[i] = src[i];
}
}
void Test5()
{
int a1[] = { 1,2,3,4,5 };
int a2[5];
Copy(a2, a1, 5);//程序运行使用特化的int,其中的IsPOD为TrueType,Get函数返回真,调用浅拷贝
string s1[] = { "111","222","333" };//string类型没有特化,其中的IsPOD为FalseType,Get函数返回假,调用赋值拷贝
string s2[3];
Copy(s2, s1, 3);
}