函數模板也可以提前聲明,不過聲明時需要帶上模板頭,並且模板頭和函數定義(聲明)是一個不可分割的整體,它們可以換行,但中間不能有分號。
類模板,在類外定義成員函數時不僅要加模板頭,在類名的後面還有加上類型參數
例如:
template<typename T1, typename T2>
void Point<T1, T2>::setX(T1 x){
m_x = x;
}
類模板在實例化時(創建對象時)必須顯式地指明數據類型,編譯器不能根據給定的數據推演出數據類型
函數模板常重載
函數模板和普通函數一樣可以重載
類模板創建對象時需要顯示指明實參類型,函數模板則不需要,那麼函數模板的實參是如何推斷出來的呢?
模板實參推斷過程中的類型轉換
普通函數調用時的參數轉換包括:
- 算術轉換 int轉float char 轉int
- 派生類向基類轉換
- const轉換
- 數組和數組指針轉換
模板函數只能進行的轉換: - const轉換
- 數組或函數指針轉換
template<typename T> void func1(T a, T b);
template<typename T> void func2(T *buffer);
template<typename T> void func3(const T &stu);
template<typename T> void func4(T a);
template<typename T> void func5(T &a)
int name[20];
Student stu1("張華", 20, 96.5); //創建一個Student類型的對象
func1(12.5, 30); //Error
func2(name); //name的類型從int[20] 換轉換爲int *,所以 T 的真實類型爲 int
func3(stu1); //非const轉換爲const,T 的真實類型爲 Student
func4(name); //name的類型從int[20] 換轉換爲 int *,所以T的真實類型爲int *
func5(name); //name的類型依然爲int[20],不會轉換爲 int *,
//所以T的真實類型爲 int [20]
;
當函數形參是引用類型時,數組不會轉換爲指針,以下爲例
template<typename T> void func(T &a, T &b);
int str1[20];
int str2[10];
func(str1, str2);//error
由於 str1、str2 的類型分別爲 int [20] 和 int [10],
在函數調用過程中又不會轉換爲指針,所以編譯器不知道應該將 T 實例化爲 int [20]
還是 int [10],導致調用失敗。
爲函數模板顯式地指明實參
和類模板顯示指定實參一樣,顯式指明的模板實參會按照從左到右的順序與對應的模板參數匹配:第一個實參與第一個模板參數匹配,第二個實參與第二個模板參數匹配,以此類推。只有尾部(最右)的類型參數的實參可以省略,而且前提是它們可以從傳遞給函數的實參中推斷出來。
template<typename T1, typename T2> void func(T1 a){
T2 b;
}
調用時只有一個參數T1,無法確定T2的類型,因此需要對T2指明實參,
因爲T2是第二個參數,所以同時也要對第一個參數T1指明實參
template<typename T1, typename T2> void func(T2 a){
T1 b;
}
調用時只有一個參數T2,無法確定T1的類型,因此需要對T1指明實參,
因爲T2是第二個參數,所以可以只指明第一個實參T1,T2可以自動推斷出來
可以省略
顯示指明實參可以進行類型轉換
template<typename T> void func(T a, T b);
func(10, 23.5); //Error
不知道把int轉爲float還是把float轉爲int
func<float>(20, 93.7); //Correct
顯示指明轉爲float