1. 程式人生 > >c++模板之萃取

c++模板之萃取

假如,我們要設計一個_Copy的模板函式。我們為了提高效率採用memcpy,可以這樣寫:

template<typename T>
T* _Copy(T* dest, T* src, size_t n)
{
        memcpy(dest, src, sizeof(T)*n);
        return dest;
}

我們知道一般的型別(比如int,float,double,char等)進行復制的時候採用memcpy效率會高一些;而像string或者是其他的一些自定義型別(並且成員有指標型別的話),繼續用mencpy將出現錯誤,採用for迴圈進行一個一個複製(賦值運算子過載)才是正確的方法。

自定義型別for迴圈程式碼:

template<typename T>
T* _Copy(T* dest, T* src, size_t n)
{
    for (size_t i = 0; i < n; i++)
    {
        dest[i] = src[i];       //相當與呼叫string的賦值運算子過載
    }
    return dest;
}

但是採用for迴圈拷貝效率明顯不如memcpy函式高,如何才能讓程式在執行內建型別時呼叫memcpy,而拷貝自定義型別時防止錯誤呼叫for迴圈拷貝,兩者兼顧呢??

為了進行不同的型別呼叫不同的方式進行拷貝,我們可以利用模板及模板的特化,在特化中返回它的型別進而進行判斷要進行那種方式的拷貝。為了統一,也可在模板即特化中重新命名它的型別,當所給的型別與所有特化有匹配時,執行一種方式進行拷貝;當所給的型別與所有特化沒有匹配時,執行另一種方式進行拷貝。

以下是原始碼:

#include <iostream>
using namespace std;
#include <string>
struct _TureType
{
    bool get()
    {
        return true;
    }
};
struct _FalseType
{
    bool get()
    {
        return false;
    }
};


//型別萃取
template<typename T>
struct TypeTraits      
{
    typedef _FalseType _IsPodType;
};
//特化TypeTraits進行型別判斷(由於內建型別已經確定,而自定義型別不確定,因此經常特化內建型別)
template<> struct TypeTraits<int> { typedef _TureType _IsPodType; }; template<> struct TypeTraits<unsigned int> { typedef _TureType _IsPodType; }; template<> struct TypeTraits<double> { typedef _TureType _IsPodType; }; template<> struct TypeTraits<float> { typedef _TureType _IsPodType; }; template<> struct TypeTraits<char> { typedef _TureType _IsPodType; }; template<> struct TypeTraits<unsigned char> { typedef _TureType _IsPodType; }; template<> struct TypeTraits<short> { typedef _TureType _IsPodType; }; template<> struct TypeTraits<long> { typedef _TureType _IsPodType; }; template<> struct TypeTraits<long long> { typedef _TureType _IsPodType; }; /*根據需要繼續特化.................*/ template<typename T> T* _Copy(T* dest, T* src, size_t n, _TureType) { memcpy(dest, src, sizeof(T)*n); return dest; } template<typename T> T* _Copy(T* dest, T* src, size_t n, _FalseType) { for (size_t i = 0; i < n; i++) { dest[i] = src[i]; //相當與呼叫string的賦值運算子過載 } return dest; } template<typename T> T* _Copy(T*dest, T* src, size_t n) { return _Copy(dest, src, n, TypeTraits<T>::_IsPodType()); } //測試普通型別 void test1() { int a[10] = { 2, 2, 3, 4, 5, 6, 7, 8, 8 }; int b[10] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; _Copy(a, b, 5); } //特化自定義型別 void test2() { string a[5] = { "abc", "def", "ghi", "123", "456" }; string b[4] = {"111111111111111111111111111111111111111", "222222", "333333", "44444444"}; _Copy(a, b, 3); } int main() { //test1(); test2(); system("pause"); return 0; }

簡單呼叫關係圖如下:

這裡寫圖片描述