16.1.1 定義函數模板
使用template+模板參數列表來定義一個函數模板。
template<typename T>
bool compare(const T&a,const T&b){
return a<b;
}
compare(1,1);
在具體調用時,會根據傳入的實參類型,將函數模板中的模板參數替換掉,轉換爲一個具體的函數實例。 這個過程叫做實例化。函數模板可以根據傳入的實參類型推斷出模板參數類型,前提是所有的模板參數類型都用到,我們也可以自己指定參數類型。
compare<int,int>(1,1);
我們可以使用typename和class聲明模板參數,但是一般使用typename,因爲這樣更加的清晰,class是舊版本遺留下來的。
使用typename和class聲明的參數模板是一個類型,但是這個類型具體是什麼要在根據傳入的實參類型來確定。我們還可以當以非類型模板參數,非類型模板參數它本身就已經是一個具體的類型的變量了,這個值由用戶提供或者編譯器推斷。
下面的調用方式就是由編譯器自己推斷得出的,用來獲取數組的大小。
template<typename value_type, unsigned arr_size>
constexpr unsigned get_arr_size(value_type(&arr)[arr_size]) {
return arr_size;
}
int a[] = {1,2,3,4,54,56};
int b[get_arr_size(a)];
下面這種就是用戶自己指定的
template<typename T,unsigned vlaue>
void print(T v) {
cout<<v<<endl;
}
print<int, 1>(233);
模板函數一樣的可以被inline和constexpr修飾。
模板的聲明和定義都放在一塊且放在頭文件中,而不是像普通的類一樣,聲明和定義分別在頭文件和源文件中
函數模板的很多錯誤都是在實例化的階段報告。
練習
16.1
實例化就是爲模板創建一個具體的例子,在函數模板中體現是函數模板根據傳入的實參類型將模板參數變爲實參的類型生成一個具體的函數。
16.2
如果傳入一個int和一個double類型的變量則會報錯,因爲函數模板無法實例化出一個形參列表爲int,double的compare
template <typename T>
bool compare(const T& a, const T&b) {
return a < b;
}
cout<<compare(1, 2)<<endl;
cout<<compare(2.2, 2.2)<<endl;
16.3
編譯報錯,提示Sales_date沒有重載<運算符
cout<< compare(data1, data2)<<endl;
16.4
template <typename Iter_type,typename Value_Type>
Iter_type my_find(const Iter_type& begin,const Iter_type& end,Value_Type target_value) {
Iter_type target_iter = end;
for (Iter_type iter = begin;iter!=end;++iter)
{
if (*iter==target_value)
{
target_iter = iter;
break;
}
}
return target_iter;
}
16.5
template<typename value_type,unsigned arr_size>
void print(value_type (&arr)[arr_size]) {
for (auto item :arr)
{
cout << item << endl;
}
}
int a[] = {1,2,3,4,54,56};
double b[] = {2,3,4,54,654};
string c[] = {"12312","2222","6666"};
print(a);
print(b);
print(c);
16.6
標準庫對數組的begin和end,很可能也是使用模板函數,對於begin則返回首元素地址,對於end則返回首元素地址+元素個數
template<typename value_type, unsigned arr_size>
value_type* my_end(value_type(&arr)[arr_size]) {
return arr + arr_size;
}
template<typename value_type, unsigned arr_size>
value_type* my_begin(value_type (&arr)[arr_size]) {
return arr;
}
int a[] = {1,2,3,4,54,56};
for (auto iter = my_begin(a); iter !=my_end(a);++iter)
{
cout << *iter << endl;
}
16.7
template<typename value_type, unsigned arr_size>
constexpr unsigned get_arr_size(value_type(&arr)[arr_size]) {
return arr_size;
}
//因爲創建數組需要輸入常量表達式,爲了驗證
//返回的是常量表達式所以使用get_arr_size()的實例
//創建一個數組
int a[] = {1,2,3,4,54,56};
int b[get_arr_size(a)];
auto value = get_arr_size(a);
cout << value << endl;
16.8
截圖來自C++ Primer第97頁,一個直接的原因是對迭代器使用!=在所有的標準庫容器上都是可以使用的,但是<符號則不一定適用,有些容器沒有定義<,比如關聯式容器,list等等,因此爲了更加的讓代碼更加通用在迭代器和指針的遍歷中使用!=更好。