C++類型萃取(分文件管理)

C++類型萃取(分文件管理)類型萃取
類型萃取是基於c++中的模板特化來實現的,是對於模板特化的應用。linux

以通用的拷貝函數爲例ios

拷貝函數,c++自帶的拷貝函數是俗稱的淺拷貝,淺拷貝對於一些內置類型而言不會出錯,但對於一些自定義類型在拷貝的時候就會出現內存訪問錯誤(中斷),想回顧淺拷貝的「同志」能夠看https://blog.51cto.com/14233078/2442527
C++類型萃取(分文件管理)1.此方案雖然解決了拷貝問題,可是缺點也很明顯,在每一次拷貝數據,都須要遍歷一遍,時間複雜度O(1)c++

#include<iostream>
using namespace std;
#include<string>

template<class T>
void Copy1(T* dst, T* src, size_t size)
{
    memcpy(dst, src, sizeof(T)*size);
}

// 優勢:必定不會出錯
// 缺陷:O(N)
template<class T>
void Copy2(T* dst, T* src, size_t size)
{
    for (size_t i = 0; i < size; ++i)
        dst[i] = src[i];
}

bool IsPODType(const char* strType)
{
    // 此處能夠將全部的內置類型枚舉出來
    const char* strTypes[] = { "char", "short", "int", "long", "long long", "float", "double" };
    for (auto e : strTypes)
    {
        if (strcmp(strType, e) == 0)
            return true;
    }

    return false;
}

template<class T>
void Copy(T* dst, T* src, size_t size)
{
    // 經過typeid能夠將T的實際類型按照字符串的方式返回
    if (IsPODType(typeid(T).name()))
    {
        // T的類型:內置類型
        memcpy(dst, src, sizeof(T)*size);
    }
    else
    {
        // T的類型:自定義類型---緣由:自定義類型中可能會存在淺拷貝
        for (size_t i = 0; i < size; ++i)
            dst[i] = src[i];
    }
}

void TestCopy()
{
    int array1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    int array2[10];
    Copy(array2, array1, 10);

    string s1[3] = { "1111", "2222", "3333" };
    string s2[3];
    Copy(s2, s1, 3);
}

int main()
{
    TestCopy();
    return 0;
}

C語言參與編譯的是.c文件,一個.c文件是一個編譯單元。
頭文件在預處理階段被展開,即,預處理器看見#include預處理指令的時候,就用相應頭文件的內容替換掉這個#include預處理指令(把頭文件內容拷貝到.c文件中,而後刪除這條#include預處理指令)。
你應該把頭文件看出是導出給外部模塊使用的接口,裏面存放外部模塊須要使用的宏定義及函數原型。
在linux下,能夠用gcc -E查看預處理以後的文件。
頭文件中的函數原型是提供給編譯器做爲函數原型檢查的,對於不是本源文件中的函數,編譯過程當中並不會產生實際的調用代碼(函數調用須要知道確切的函數地址),只是在相應的地方作個標記,表示在這裏須要調用某個函數。編譯完成產生的是彙編代碼。
如上所述,編譯產生的彙編代碼並不能直接運行,由於外部函數調用的地方還沒給予確切的函數地址。這個工做由連接過程完成。連接器會查找其它源文件所產生的彙編代碼,進而找到正確的函數調用地址,而後用這個地址替換掉在編譯時作的標記。完成這一步後,程序就能夠實際運行了。
所以,.h是根本不會被編譯的,它若是被包含,則會被預處理器將其內容一分不差的拷貝到.c文件中,.編譯器編譯的是拷貝後的這個.c文件。ide

2.分文件管理:
由於頭文件在預處理階段就已完成,因此不會下降代碼效率,所以解決1中代碼效率低的問題函數

頭文件測試

#pragma once

#include<iostream>
using namespace std;
#include<string>

//來自自定義類型
struct TrueType
{};

// 對應自定義類型
struct FalseType
{};

//隱示實例化
template<class T>
struct TypeTraits
{
    typedef FalseType PODTYPE;  // plain old data
};

//顯示實例化
template<>
struct TypeTraits<char>
{
    typedef TrueType PODTYPE;
};

template<>
struct TypeTraits<short>
{
    typedef TrueType PODTYPE;
};

template<>
struct TypeTraits<int>
{
    typedef TrueType PODTYPE;
};
template<>
struct TypeTraits<long>
{
    typedef TrueType PODTYPE;
};

template<>
struct TypeTraits<long long>
{
    typedef TrueType PODTYPE;
};

template<>
struct TypeTraits<float>
{
    typedef TrueType PODTYPE;
};

template<>
struct TypeTraits<double>
{
    typedef TrueType PODTYPE;
};

void TestCopy();

源代碼spa

#include"Type_extraction.h"

template<class T>
void Copy(T* dst, T* src, size_t size, TrueType)
{
    // T的類型:內置類型
    memcpy(dst, src, sizeof(T)*size);
}

template<class T>
void Copy(T* dst, T* src, size_t size, FalseType)
{
    // T的類型:自定義類型---緣由:自定義類型中可能會存在淺拷貝
    for (size_t i = 0; i < size; ++i)
        dst[i] = src[i];
}

template<class T>
void Copy(T* dst, T* src, size_t size)
{
    Copy(dst, src, size, TypeTraits<T>::PODTYPE());
}

void TestCopy()
{
    int array1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    int array2[10];
    Copy(array2, array1, 10);

    string s1[3] = { "1111", "2222", "3333" };
    string s2[3];
    Copy(s2, s1, 3);
}

測試文件main.c.net

#include"Type_extraction.h"

int main()
{
    TestCopy();
    return 0;
}

模板的聲明和定義必須放在一個文件緣由
https://blog.csdn.net/chigusakawada/article/details/78752668
顯示實例化,隱式實例化概念
https://blog.csdn.net/qiujianjian/article/details/84792608code

相關文章
相關標籤/搜索