C++中的特化問題和型別萃取問題
阿新 • • 發佈:2019-02-08
模板的特化
概念
從字面上來解釋,就是為已有的模板引數進行一些使其特殊化的指定,使得以前不受任何約束的模板引數,或受到特定的修飾(例如const或者搖身一變成為了指標,甚至是經過別的模板類包裝之後的模板型別)或完全被指定了下來。
全特化:
就是模板中模板引數全被指定為確定的型別。全特化也就是定義了一個全新的型別,全特化的類中的函式可以與模板類不一樣。
偏特化:
就是模板中的模板引數沒有被全部確定,需要編譯器在編譯時進行確定。
全特化的標誌就是產生出完全確定的東西,而不是還需要在編譯期間去搜尋適合的特化實現
模板類全特化
template <class T1,class T2>
class KeyVal
{
protected:
T1 _key;
T2 _val;
};
//全特化
template<>
class KeyVal<int,char>
{
protected:
int _key;
char _val;
};
這裡歸納下針對類模板特化的幾種型別
- 一是特化為絕對型別;
- 二是特化為引用,指標型別;
- 三是特化為另外一個類模板。
模板類的偏特化
template <class T1,class T2>
class KeyVal
{
protected:
T1 _key;
T2 _val;
};
template <class T2> //區域性特化
class KeyVal<int,T2>
{
protected:
int _key;
T2 _val;
};
template <class T1,class T2> //區域性特化
class KeyVal<T1*,T2*>
{
protected:
T1 _key;
T2 _val;
};
從上面的例子可以看出區域性特化偏特化並不僅僅是指特化部分引數,而是針對模板引數更進一步的條件限制所設計出來的一個特化版本。
模板函式全特化
template <class T>
void Display(const T& x)
{
cout<<x<<endl;
}
template <>//模板函式全特化
void Display(const int& x)
{
cout<<x<<endl;
}
全域性函式模板特化不能包含預設的實參值。然而,對於基本(即要被特化的)模板所指定的任何預設實參,顯式特化版本都可以應用這些預設實參值。
模板函式不支援區域性特化。
全域性特化和區域性特化都沒有引入一個全新的模板或者模板例項。它們只是對原來的泛型(或者非特化)模板中已經隱式宣告的例項提供另一種定義。在概念上,這是一個相對比較重要的現象,也是特化區別於過載模板的關鍵之處。
型別萃取
當我們在寫Vector和List的時候,遇到了這樣的問題,在拷貝建構函式中和順序表擴容時,當是內建型別我們可以直接使用memcpy把舊空間的內容考到新空間,但是當遇到strring型別時使用memcpy就會發生淺拷貝問題,會造成對一塊空間同時析構多次。當時為了解決這個問題就統一使用了深拷貝。顯然這樣的解決方法不是最優的。如果我們可以確定型別,當是內建型別時就用memcpy,遇到string型別時就是用深拷貝。
型別萃取程式碼實現
struct __TrueType
{};
struct __FalseType
{};
template<class T>
struct TypeTraits
{
typedef __FalseType IsPodType;
};
template<class T>
T* __TypeCopy(const T* src,T* dst,size_t n,__TrueType)
{
cout<<"memcpy"<<endl;
return (T*)memcpy(dst,src,n*sizeof(T));
}
template<class T>
T* __TypeCopy(const T* src,T* dst,size_t n,__FalseType)
{
cout<<"for+operator= "<<endl;
for (size_t i=0; i<n; i++)
{
dst[i] = src[i];
}
return dst;
}
template<class T>
T* TypeCopy(const T* src,T* dst,size_t n)
{
return __TypeCopy(src,dst,n,TypeTraits<T>::IsPodType());
}
template<>
struct TypeTraits<int>
{
typedef __TrueType IsPodType;
};
template<>
struct TypeTraits<char>
{
typedef __TrueType IsPodType;
};
template<>
struct TypeTraits<double>
{
typedef __TrueType IsPodType;
};
template<>
struct TypeTraits<float>
{
typedef __TrueType IsPodType;
};
測試程式碼:
void TestType()
{
int srcint[5]={1,2,3,4,5};
int dstint[5];
string srcstr[3]={"11","22","33"};
string dststr[3]={};
TypeCopy(srcint,dstint,5);
TypeCopy(srcstr,dststr,3);
}
測試結果: