C++】模板特化的应用---类型萃取

試著忘記壹切 提交于 2020-02-27 00:46:39

在C++中,内置类型的遍历,我们只需要进行浅拷贝就可以,但自定义类型就不一定了。比如之前类与对象中,如果类中对象涉及到资源,我们使用深拷贝的方式进行拷贝构造等操作,如果不涉及资源,则使用简单的浅拷贝,在模拟实现string类\vector等中也遇到。这样虽然可以,但代码效率低。
所以,为了将内置类型与自定义类型区分开,就有了类型萃取,它是类模板特化的应用。那么我们先来了解类模板特化以及非类型模板参数
非类型模板参数

模板参数分为类型形参与非类型形参
在这里插入图片描述
注意:

  • 浮点数,类对象以及字符串是不允许作为非类型模板参数的
  • 非类型模板参数必须在编译期就能确认结果

模板的特化

有时我们使用模板实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,看下面代码
代码1

template<class T>
T MAX(T left, T right)
{
 return left > right ? left : right;
}
int main()
{
 char* p1 = "world";
 char* p2 = "hello";
 cout << MAX(p1, p2) << endl;

比较字符串大小时,这里面比较的是指针类型,因此不管p1、p2是什么字符串,打印的都是p2,所以如果不直接将函数直接给出,用模板的话,就要将模板特化了
代码2

//格式就是这样
template<>
char* MAX<char*>(char*& left, char*& right)//函数形参表必须要和模板函数的基础参数类型完全相同
{
 if (strcmp(left, right) > 0)
  return left;
 return right;
}

代码2则是对代码1 函数模板的特化,上面一般情况函数模板遇到不能处理或者处理有误的类型,为了简单通常都是将该函数直接给出。
关于模板特化,主要是阐述下类模板特化

类模板特化

分为全特化和偏特化
全特化就是将模板擦书类表中所有的参数都确定化
偏特化就是针对模板参数进一步进行条件限制,其中,部分特化是将模板参数中的一部分参数特化;参数更进一步的限制是针对模板参数更进一步的条件限制所设计出来的一个特化版本
在实例化时,调用对应的版本,如果没有,就调用普通的类模板,看代码就理解了
代码3

template<class T1,class T2>
class Data
{
public:
 Data(){cout << "Data<T1,T2>" << endl;}
private:
 T1 _d1;
 T2 _d2;
};
template<>
class Data<int, char>//全特化,将所有参数都确定话
{
public:
 Data(){ cout << "Data<int,char>" << endl; }
private:
 int _d1;
 char _d2;
};
template<class T1>
class Data<T1, int>//部分特化  第一个参数任意类型都可以
{
public:
 Data(){ cout << "Data<int,char>" << endl; }
private:
 T1 _d1;
 char _d2;
};
int main()
{
 Data<int, double> d1;//调用基础版本
 Data<int, char> d2;//调用全特化版本
 Data<char, int> d3;//调用部分特化
 return 0;
}

类型萃取—类模板特化的应用

可以将内置类型与自定义类型区分开
我们将用TrueType代表内置类型,FalseType代表自定义类型,定义TypeTraits,给类型都取别名IsPODType,如果是内置类型则调用对应的类模板特化,如果是自定义得得到F进行浅拷贝Type,通过循环进行赋值深拷贝。代码如下:

//代表内置类型/////////////////////////////////////////////////////
struct TrueType
{
 static bool Get(){return true;}
};
//代表自定义类型
struct FalseType
{
 static bool Get(){return false;}
};
//用户对类模板进行实例化,T可以是任意类型////////////////////////////
template<class T>//自定义类型特化
struct TypeTraits
{
 typedef FalseType IsPODType;//定义别名
};
/////////////////////////////////////////////////////////////////////
template<>//内置类型特化
struct TypeTraits<char>
{
 typedef TrueType IsPODType;
};
template<>
struct TypeTraits<short>
{
 typedef TrueType IsPODType;
};
template<>
struct TypeTraits<int>
{
 typedef TrueType IsPODType;
};
template<>
struct TypeTraits<long>
{
 typedef TrueType IsPODType;
};
//所有内置类型都特化一下...
//////拷贝函数/////////////////////////////////////////////////////
template<class T>
void Copy(T* dst, const T* src, size_t size)
{
 if (TypeTraits<T>::IsPODType::Get())//识别出类型
  memcpy(dst, src, sizeof(T)*size);
 else//如果不是上述类型
 {
  for (size_t i = 0; i < size; ++i)
   dst[i] = src[i];
 }
}
/////test///////////////////////////////////////////////////////
int main()
{
 int a1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 int a2[10];
 Copy(a2, a1, 10);//内置类型就调用内置类型的版本  浅拷贝
 string s1[] = { "1111", "2222", "3333", "4444" };
 string s2[4];
 Copy(s2, s1, 4);//自定义就调用自定义类型   深拷贝
 return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!