个人博客传送门
类型萃取,是C++中的一种编程技术。当我们希望对模板传递的不同类型进行不同的操作的时候,同时我们又不希望改变该模板的封装方式。我们可以通过这种技术,对传入的不同类型进行不同的原理操作。
特化
要明白类型萃取,首先要知道模板中的特化。一般来说,我们的模板是通用类型的,但是如果有一些类型,我们希望有不同的操作方式,我们就可以通过特化的方式。例子如下:
#include <iostream>
using namespace std;
//模板的一般版本
template <class T>
class number{
public:
void show(){
cout << "number" << endl;
}
};
//模板的int类型特化版本
template <>
class number<int>{
public:
void show(){
cout << "int" << endl;
}
};
int main(){
system("clear");
number<int> numint;
numint.show();
number<float> numfloat;
numfloat.show();
number<char> numchar;
numchar.show();
return 0;
}
只有int类型才会输出int,其它的就像是float和char类型输出的都是number
特化的方式,其实是十分冗余的。如果我的number类有很多的封装,那么实现它的特化,就需要将这些封装重新实现一遍。这样的复用性就十分低。
类型萃取TypeTraits
关于类型萃取的知识,可以看看我的这篇读书笔记中的3.3和3.4
我的个人博客文章地址
我的CSDN博客文章地址
这里我进行一个对于自创类SeqList类(对STL中vector的模拟)的类型萃取举例,情景说明:这里我想要对模板类SeqList进行拷贝,涉及到一个问题。如果我的元素类型是string的话,我必须进行深拷贝,否则就会出现奔溃的情况,这是对内存的使用出现问题。当我的元素类型是int、float、char等平凡类型(即POD:plain old data,基本类型,这些类型的拷贝不会涉及到内存的使用异常),我就可以使用浅拷贝,这样比起深拷贝提高了效率。
这个时候,我通过在SeqList类中进行类型萃取,就可以实现两种不同的拷贝方式:
//定义两个空类
struct __TrueType{};
struct __FalseType{};
//一般类型及特化(内嵌重定义IsPODType)
template<class T>
struct __TypeTraits{ typedef __FalseType IsPODType; };
template<>
struct __TypeTraits<int>{ typedef __TrueType IsPODType; };
//实现功能函数(用__TrueType/__FalseType实现重载)
template <class T>
T* __TypeCopy(T* dst, const T* src, size_t n, __TrueType){
//浅拷贝,调用memcpy
return (T*)memcpy(dst, src, n*sizeof(T));
}
template <class T>
T* __TypeCopy(T* dst, const T* src, size_t n, __FalseType){
//深拷贝,进行了 operator= 调用
for(size_t i = 0; i<n; ++i){
dst[i] = src[i];
}
return dst;
}
//对外接口(实现IsPODType的__TrueType和__FalseType的转换)
template <class T>
T* TypeCopy(T* dst, const T* src, size_t n){
return __TypeCopy(dst, src, n, __TypeTraits<T>::IsPODType);
}
//调用
int main(){
int a1[3] = {1, 2, 3};
int a2[2] = {0, 0, 0};
string s1[3] = {"1", "2", "3"};
string s2[3] = {"0", "0", "0"};
TypeCopy(a1, a2, 3);
TypeCopy(s1, s2, 3);
return 0;
}
这样,当传入的参数是s1,s2的时候,__TypeTraits
调用的是一般版本,IsPODType
为__FalseType
,这样__TypeCopy
调用的是__FalseType
的重载版本,进行深拷贝。当传入的参数是a1,a2的时候,调用的是__TrueType
的重载版本,进行浅拷贝。这里只对int进行了特化,所以只有int可以调用__TrueType
的版本。但是我们可以对float、double等PODType进行特化,这样就大大提高了代码的复用性。