模板的特化和萃取

xiaoxiao2021-02-27  595

模板的特化可以分为全特化和偏特化,全特化是全部参数进行特化,但是偏特化的话是部分参数,或者某些模板参数的进一步限制。

首先来看模板全特化的例子:

#include<iostream> using namespace std; template <class T> class Seqlist { public: Seqlist() { cout << "Seqlist<T>->memcpy" << endl; } }; template<> class Seqlist<string> { public: Seqlist() { cout << "Seqlist<string>->for()" << endl; } }; int main() { Seqlist<int>s1; Seqlist<string>s2; return 0; } 其输出结果为:

写一个偏特化的例子:

#include<iostream> using namespace std; template < class T1, class T2> class Data { public: Data() { cout << "Data<T1,T2>" << endl; } protected: T1 a1; T2 a2; }; template<class T2> class Data<int, T2> { public: Data() { cout << "Data<int,T2>" << endl; } protected: int a1; T2 a2; };我们了解了全特化和偏特化,来看看特化的作用,来看下面的例子:

#include<iostream> using namespace std; template<class T> T* Copy(T* dst, T* src, size_t n) { return (T*)memcpy(dst,src, sizeof(T)*n); } int main() { int a1[5] = { 1, 2, 3 }; int a2[5] = { 0 }; Copy(a2, a1, 5);//把a1中的值拷贝到a2中,拷了10个对象 string s1[5] = { "10", "20", "30" }; string s2[5] = {}; Copy(s2, s1, 5); return 0; }我们打开监视可以看到:

但是上面这个程序会出现错误,比如把string中s1“10”改为“11111111111111111111111111”程序就会出现崩溃,因为此时拷贝为浅拷贝,而当s1当中的字符串比较短时就存在于s1中的buffer中,但是当字符串比较长时,该字符串不存在于buffer中,而是在堆上动态开辟了一段空间,当析构时会把这段空间析构两次,所以就会出现错误,而为了避免这种错误我们可以特例话string,并且为它单独写一份析构函数,而另一种简单的方法就是进行萃取,其实萃取就是特化,萃取的目的就是为了提高效率。

创建一个萃取的头文件:

struct _TrueType {}; struct _FalseType {}; template<class T> struct TypeTraits { //内嵌定义类型(在类中定义类) //POD:plain old data,平凡类型 typedef _FalseType IsPodType; }; template<> struct TypeTraits<int> { //内嵌定义类型(在类中定义类) //POD:plain old data,平凡类型 typedef _TrueType IsPodType; };然后在元文件中:

#include<iostream> #include"TypeTraits.h" using namespace std; template<class T> T* _Copy(T* dst, T* src, size_t n,_TrueType) { return (T*)memcpy(dst,src, sizeof(T)*n);//如果是内置类型就调用memcpy } template<class T> T* _Copy(T* dst, T* src, size_t n,_FalseType) { for (size_t i = 0; i < n; ++i)//如果是自定义类型就调用for循环 { dst[i] = src[i]; } return dst; } template<class T> T* _Copy(T* dst, T* src, size_t n) { return _Copy(dst, src, n, TypeTraits<T>::IsPodType()); } int main() { int a1[5] = { 1, 2, 3 }; int a2[5] = { 0 }; _Copy(a2, a1, 5);//把a1中的值拷贝到a2中,拷了10个对象 string s1[5] = { "10", "20", "30" }; string s2[5] = {}; _Copy(s2, s1, 5); return 0; }我们来分析这个程序的走向:当程序运行到_Copy(a2,a1,10)时首先判断是不是平凡类型,判断是,则运行memcpy;当程序运行到_Copy(s2,s1,10)时判断出不是平凡类型,则运行for循环。

转载请注明原文地址: https://www.6miu.com/read-359.html

最新回复(0)