模板
- 函數模板
- 類模板
函數模板
函數模板的格式為:
template<typename T1,typename T2...>
函數返回值類型 函數名(參數列表)
{//函數體
}
typename是定義模板參數的關鍵字,可以使用class來代替(不能使用struct)
函數模板本身并不是函數,在編譯階段,編譯器通過用戶傳參自動識別參數類型,從而推導出模板函數參數列表的類型,得到一個函數供用戶使用,這樣就可以通過用戶傳遞的參數類型的不同,得到一批僅僅只是類型不同的函數,相當于把重復做的事情交給了編譯器,從而提升了開發效率。
當編譯器對同一typename推到出不同類型時會出錯:
template<typename T>
void swap(T& num1,T& num2)
{T temp=num1;num1=num2;num2=temp;
}int main()
{int num1=1;float num2=2.0;swap(num1,num2);//T被推導出不同的類型,出錯
}
類似于上面的swap函數由編譯器自動推導typename的類型的稱為隱式實例化,還有一種實例化方式為顯式實例化:
函數名 <指定類型>(參數)
有些場景只能使用顯式實例化
template<typename T>
T* fun(int n)//所有參數已經是特定類型
{return (T*)malloc(n);
}int main()
{int n=100;int*p=fun<int>(n);//顯式實例化return 0
]
要注意在顯式實例化中<>里面的類型個數要與template的<>中的typename的個數相同,同時是自左向右依次匹配typename的類型。
模板參數匹配原則:
①一個非模板函數與一個同名的模板函數同時存在,且該模板函數可以實例化出這個非模板函數時,優先使用非模板函數。
int Sum(int num1, int num2)
{cout << "非模板函數" << endl;return 0;
}template<typename T1,typename T2>
int Sum(T1 num1, T2 num2)
{cout << "模板函數" << endl;return 0;
}
int main()
{int num1=1;int num2=2;Sum(num1, num2);//優先使用非模板函數Sum<int, int>(num1, num2);//使用模板函數return 0;
}
②當非模板函數參數類型不匹配,而模板可以實例化出一個參數更匹配的函數時,優先使用模板實例化函數
int Sum(int num1, int num2)
{cout << "非模板函數" << endl;return 0;
}template<typename T1,typename T2>
int Sum(T1 num1, T2 num2)
{cout << "模板函數" << num2<<endl;return 0;
}
int main()
{int num1=1;float num2=2.0;//浮點型Sum(num1, num2);//優先使用模板實例化函數return 0;
}
總的來說就是哪個參數更匹配就優先使用哪個,如果兩個參數都匹配就優先使用現成的(非模板函數)。
類模板
類模板的定義格式為:
template<class T1,class T2...>
class 模板類類名
{//類體
};//注意這里有分號
模板類的成員函數的聲明和定義分離時,形式如下:
template<class T>
class MyVector
{
public:viod fun1();//函數聲明
private://...
};//函數定義
template<class T>
void MyVector<T>::fun()//注意返回值類型的位置
{//...
}
模板類的實例化格式為:
模板類類名<數據類型> 類名
模板類的類名不是真正的類,而實例化才是真正的類
MyVector<int> s;
//實例化出一個類后,利用該類實例化出一個對象s
需要注意的是類模板不能將聲明和定義分離到兩個文件中。