1. 程式人生 > >c++模板函數

c++模板函數

clas 實例 定義 HR pan 是把 init 傳統 oid

模板特化(也有翻譯為模板具體化)(specialization)

??如果把模板函數當作數學歸納法的話,模板特化就是n=常數C的情況。

//模板函數聲明
template <typename T>
bool greater(const T &a,const T &b);
int main()
{
    return 0;
}
//模板函數定義
template <typename T>
bool greater(const T &a,const T &b)
{
    if(a > b)
        return true;
    else
return false; }

??如果上面的T是char*類型,那麽這種比較是不符合我們要求的,它比較的是地址,char*應該用strcmp。

??如果按照我們最簡單的思路的話就是直接將T換成char*,但這樣編譯卻給出了error,說這個特化找不到對應的模板函數。

#include <cstring>
//模板函數聲明
template <typename T>
bool greater(const T &a,const T &b);
//特化的模板函數的聲明
template<>
bool greater<char*>(const
char * &a,const char * &b); int main() { return 0; } //模板函數定義 template <typename T> bool greater(const T &a,const T &b) { if(a > b) return true; else return false; } //特化的模板函數的定義 template<> bool greater<char *>(const char * &a,const char
* &b) { return strcmp(a,b)>0?true:false; }

??我們模板函數的定義const T &a,其實也可以是這種寫法T const &a,這兩種寫法表明const和T分別修飾a,也就是a的類型既是const又是T;而不是const T作為一個整體,a的類型是const T。雖然在這個問題上,這兩種理解沒有出現語義的誤解,但是在上面的例子就出現誤解了。

? 根據我們原來的模板函數的定義,我們的目的應該是這樣的特化函數的參數,const (char *) &a(是沒有這種寫法,只是為了讓我們理解方便),也就是說char *是一個整體,和const一起修飾a。const char* &a卻讓const char作為了一個類型,這顯然不是我們要的。char* const &a這才是我們想要的。

#include <cstring>
//模板函數聲明
template <typename T>
bool greater(T const &a,T const &b);
//特化的模板函數的聲明
template<>
bool greater<char*>(char * const &a,char * const &b);
int main()
{
    return 0;
}
//模板函數定義
template <typename T>
bool greater(T const &a,T const &b)
{
    if(a > b)
        return true;
    else
        return false;
}
//特化的模板函數的定義
template<>
bool greater<char*>(char * const &a,char * const &b)
{
    return strcmp(a,b)>0?true:false;
}

??如果在寫類型時,習慣將const放在char等後面,那麽寫模板特化時,直接代換T就不會出現錯誤。

??如果在寫類型時,習慣將const放在類型char等後面,那麽寫模板特化時,直接代換T就不會出現錯誤。

定義與實現分離?

??在傳統上,我們總是把定義寫在.h文件裏,而實現文件寫在.cpp文件裏,但這在模板裏面是否可以,請看下面一個例子。

//swap.h
template <typename T>
void swap(T &a,T &b);
//swap.cpp
template <typename T>
void swap(T &a,T &b)
{
    T temp = a;
    a = b;
    b = temp;
}
//main.cpp
#include "swap.h"
int main()
{
    int a,b;
    swap(a,b);
    //...
    return 0;
}

??編譯器在編譯main.cpp文件時只看到swap的定義而沒有實現,所以留空,讓連接器去鏈接swap的實現。而編譯器在編譯swap.cpp時沒有看到模板參數,所以也不會編譯,最後便會導致鏈接錯誤,即找不到swap

??所以模板函數或者模板類,應該將定義和實現放在.h文件。

顯示實例化(explict initialization)

??實例化:一個通過使用具體值替換模板參數,從模板產生的普通類,函數或者成員函數的過程。
??隱式實例化:這是編譯器看到模板函數時,在當前文件實現相應的模板參數的實例化。
??顯示實例化:就是自己手工讓編譯器在此文件實現相應的模板參數的實例化。
既然編譯器會自動實現實例化,為什麽還要我們去手工去讓編譯器實現實例化呢?請看下面的例子。

//swap.h
template <typename T>
void swap(T &a,T &b)
{
    T temp = a;
    a = b;
    b = temp;
}
//function.h
void function();
//function.cpp
#include "swap.h"
void function()
{
    int a,b;
    swap(a,b);
}
//main.cpp
#include "swap.h"
#include "function.h"
int main()
{
    int a,b;
    swap(a,b);
    function();
    //...
    return 0;
}

??為了容易看出,我們暫且用function表示一個用到swap的函數,它也可以是一個類。
??編譯器在編譯function.cpp時會用void swap

//swap.h
template <typename T>
void swap(T &a,T &b);
//swap
templatee <typename T>
void swap(T &a,T &b)
{
    T temp = a;
    a = b;
    b = temp;
}
//explict_initilization.cpp
#include "swap.cpp"
template void swap<int>(int&,int&);//顯示實例化
//function.h
void function();
//function.cpp
#include "swap.h"
void function()
{
    int a,b;
    swap(a,b);
}
//main.cpp
#include "swap.h"
#include "function.h"
int main()
{
    int a,b;
    swap(a,b);
    function();
    //...
    return 0;
}

更加詳細的介紹可以看:c++模板類(一)理解編譯器的編譯模板過程

export的用法

??為了解決上面用一個explict_initilization.cpp來管理實例化文件的不便利,c++可以export這個關鍵詞,讓編譯器和鏈接器去管理我們上面要解決的事情。

c++模板函數