引言:
模闆是一個藍圖,它本身不是類或函數。編譯器使用模闆産生指定的類或函數的特定版本。産生模闆的特定類型執行個體的過程稱為執行個體化。
模闆在使用時将進行執行個體化,類模闆在引用實際模闆類型時執行個體化,函數模闆在調用它或用它對函數指針進行初始化或指派時執行個體化。
1、類的執行個體化
當編寫Queue<int>qi時,編譯器自動建立名為Queue<int>的類。實際上,編譯器通過重新編寫Queue模闆,用類型int代替模闆形參的每次出現而建立Queue<int>類。執行個體化的類就像已經編寫的一樣:
如果要為string類型的對象建立Queue類,可以編寫:
在這個例子中,用string代替Type的每次出現。
【重點了解:】
類模闆的每次執行個體化都會産生一個獨立的類類型:為int類型執行個體化的Queue與任意其他Queue類型沒有關系,對其他Queue類型的成員也沒有特殊通路權限!
2、類模闆實參是必需的
想要使用類模闆,就必須顯式指定模闆實參:
類模闆不定義類型,隻有特定的執行個體才定義了類型。特定的執行個體是通過提供模闆實參與每個模闆形參比對而定義的。模闆實參在用逗号分隔并用尖括号包覆的清單中指定:
用模闆類定義的類型總是包含模闆實參。例如,Queue不是類型,而Queue<int>,Queue<string>是類型。
3、函數模闆執行個體化
使用函數模闆時,編譯器通常會為我們推斷模闆實參:
這個程式執行個體化了compare的兩個版本:一個用int代替T,另一個用double代替T,實質上是編譯器為我們編寫了compare的這兩個執行個體:
一、模闆實參推斷
要确定應該執行個體化哪個函數,編譯器會檢視每個實參。如果相應形參聲明為類型形參的類型,則編譯器從實參的類型推斷形參的類型。從函數實參确定模闆實參的類型和值的過程叫做模闆實參推斷。
1、多個類型形參的實參必須完全比對
模闆類型形參可以用作一個以上函數形參的類型。在這種情況下,模闆類型推斷必須為每個對應的函數實參産生相同的模闆實參類型。
如果compare的設計者想要允許實參的正常轉換,則函數必須用兩個類型形參來定義:
2、類型形參的實參的受限轉換
一般而言,不會轉換實參以比對已有的執行個體化,相反,會産生新的執行個體。除了産生新的執行個體化之外,編譯器隻會執行兩種轉換:
1)const轉換:接受const引用或const指針的函數可以分别用非const對象的引用或指針來調用,無須産生新的執行個體化。如果函數接受非引用類型,形參類型實參都忽略const,即,無論傳遞const或非 const對象給接受非引用類型的函數,都使用相同的執行個體化。
2)數組或函數到指針的轉換:如果模闆形參不是引用類型,則對數組或函數類型的實參應用正常指針轉換。數組實參将當作指向其第一個元素的指針,函數實參當作指向函數類型的指針。
3、應用于非模闆實參的正常轉換
注意下面的一段程式:
因為op2的類型是固定的,在調用sum的時候,可以對傳遞給op2的實參應用正常轉換:
4、模闆實參推斷與函數指針
可以使用函數模闆對函數指針進行初始化或指派,此時,編譯器使用指針的類型執行個體化具有适當模闆實參的模闆版本。
例如,假定有一個函數指針指向傳回int值的函數,該函數接受兩個形參,都是 constint 引用,可以用該指針指向compare的執行個體化:
pf1的類型是一個指針,指向“接受兩個constint & 類型形參并傳回int值的函數”,形參的類型決定了T的模闆實參的類型:T的模闆實參為int型,指針 pf1引用的是将 T綁定到 int的執行個體化。
擷取函數模闆執行個體化的位址的時候,上下文必須是這樣的:它允許為每個模闆形參确定唯一的類型或值。
如果不能從函數指針類型确定模闆實參,就會出錯:
對func的調用可以執行個體化下列函數中的任意一個:
因為不能為傳給func的實參确定唯一的執行個體化,該調用會産生一個編譯時(或連結時)錯誤!