函数模板(参考《C++ Templates 英文版第二版》)
C++模板編程(參考《C++ Templates 英文版第二版》)
Chapter 1 函數(shù)模板
1.1 一窺函數(shù)模板
template<class T> T max(T a, T b) {return b < a ? a : b; } #include "max1.hpp" #include <iostream> #include <string> #include <format>int main(int argc, char* argv[]) {int i = 42;std::cout << std::format("max(7,i):{}\n", ::max(7, i)); // C++20double f1 = 3.4;double f2 = -9.3;std::cout << std::format("max(f1,f2):{}\n", ::max(f1, f2));std::string s1 = "i am very intelligent";std::string s2 = "i am intelligent";/** 如果不使用::限定max為全局* 則默認(rèn)使用std::max(),對(duì)于在std空間內(nèi)的類型*/std::cout << std::format("max(s1,s2):{}\n", ::max(s1, s2)); }輸出:
max(7,i):42 max(f1,f2):3.4 max(s1,s2):i am very intelligent模板不會(huì)被編譯成一個(gè)可以處理任何類型的實(shí)例,而是不同的類型使用模板時(shí),模板會(huì)生成不同的實(shí)例
通過(guò)確定的參數(shù)代替模板參數(shù)的過(guò)程叫實(shí)例化
1.1.3 兩階段Translation
為了一個(gè)不支持相應(yīng)操作的類型實(shí)例化模板會(huì)導(dǎo)致錯(cuò)誤
例如,復(fù)數(shù)比較大小
因此,模板的"編譯"分兩步:
- 檢查語(yǔ)法錯(cuò)誤
- 使用不依賴模板參數(shù)的名字
- 檢查不依賴于模板參數(shù)的靜態(tài)斷言
有些編譯器不進(jìn)行完全的第一階段檢查,你有可能觀察不到上述現(xiàn)象
1.2 函數(shù)參數(shù)推斷(Template Argument Deduction)
當(dāng)我們調(diào)用函數(shù)模板時(shí),模板參數(shù)將由我們傳入的參數(shù)確定
但是,T 可能只是參數(shù)的"一部分",例如,我們我們使用常量引用聲明max()
template<typename T> T amx(T const& a,T const& b) {return a < b ? b : a; }在類型推斷中的類型轉(zhuǎn)換
在類型推斷中類型轉(zhuǎn)換是有限的
- 當(dāng)使用引用傳參時(shí),參數(shù)類型必須完全匹配,編譯器不會(huì)進(jìn)行任何微小的轉(zhuǎn)換
- 當(dāng)使用值傳參時(shí),支持退化的轉(zhuǎn)換,const voaltile限定符會(huì)被忽略,引用轉(zhuǎn)換為引用類型,數(shù)組,函數(shù)將會(huì)被轉(zhuǎn)換成指針類型,兩個(gè)參數(shù)退化(std::decayed)1后的類型必須匹配
有三個(gè)方法解決這個(gè)問(wèn)題:
強(qiáng)制轉(zhuǎn)換參數(shù)使他們都匹配
std::cout << std::format("max1(1,4.4):{}", ::max(static_cast<double>(1), 4.4));顯示指定參數(shù)類型
std::cout << std::format("max1(1,4.4):{}", ::max<double>(1, 4.4));默認(rèn)參數(shù)的類型推斷
template<typename T> void f(T = "") { } f(1); // OK:T 推斷為 int,調(diào)用 f<int>(1) f(); // 錯(cuò)誤:不能推斷 T如果想要支持這個(gè)例子,你也可以聲明一個(gè)默認(rèn)參數(shù)類型
f(); // OK1.3 多種參數(shù)模板
函數(shù)模板有兩種不同的參數(shù)
-
template parameters 模板參數(shù) , 尖括號(hào)里面的就是模板參數(shù)
-
call parameters 調(diào)用參數(shù),就是參數(shù)列表里面的
template<typename T> // 模板參數(shù) T max(T a,T b) // a,b就是調(diào)用參數(shù)你可以使用多個(gè)模板參數(shù)
template<typename T1,typename T2> T1 max(T1 a,T2 b) {return a < b ? b : a; }這個(gè)例子有一些問(wèn)題,雖然他很有可能正常工作,但是他可能違背程序員的意愿,將返回值強(qiáng)制轉(zhuǎn)換成T1,例如 double->int
有三種方式可以避免這個(gè)問(wèn)題:
- 再加一個(gè)模板參數(shù)作為返回值類型
- 讓編譯器清楚返回值類型
- 把返回值聲明成兩個(gè)模板參數(shù)的共同類型
我們接下來(lái)討論:
1.3.1 模板參數(shù)作為返回值
我們可以明確的指定參數(shù)類型
template<typename T> T max(T a, T b) {return a < b ? b : a; } ::max<int>(1,2.2);但是很多情況下,參數(shù)與返回值類型并沒(méi)有關(guān)系,我們就可以聲明第三個(gè)模板參數(shù)作為返回值
template<typename T1, typename T2,typename RT> RT max(T1 a, T2 b) {return a < b ? b : a; }但是模板參數(shù)推斷并不會(huì)考慮到返回值,所也這么做是不行的,除非你手動(dòng)指定返回值類型
::max<int,double,double>(1,3.3)顯然,這樣做并沒(méi)有什么優(yōu)勢(shì)
1.3.2 推斷返回值
template<typename T1,typename T2> auto max(T1 a,T2 b) {return a < b ? b : a; }auto使得真正返回值必須從函數(shù)體中推斷出來(lái)
然而,在一些情況下,函數(shù)傳入?yún)?shù)是引用類型,你想返回值類型,這時(shí)你就需要使用std::decay1去掉修飾符
template<typename T1, typename T2> auto max(T1 a, T2 b) ->typename std::decay<decltype(true?a:b)>::type {return a < b ? b : a; }1.3.3 返回公共類型(Common Type)
上面的例子可以直接這么寫
#include <type_traits>template<typename T1, typename T2> std::common_type_t<T1,T2> max(T1 a, T2 b) {return a < b ? b : a; }
1.4 默認(rèn)模板參數(shù)
你也可以定義默認(rèn)的模板參數(shù)
我們可以使用之前的模板參數(shù)
template<typename T1, typename T2,typename RT = std::decay_t<decltype(true?T1():T2())>> RT max(T1 a, T2 b) {return a < b ? b : a; }std::decay_t確保不會(huì)返回引用
我們可以使用std::common_type_t<>與std::decay相同的效果
template<typename T1, typename T2, typename RT =std::common_type_t<T1,T2>> RT max(T1 a, T2 b) {return a < b ? b : a; }1.5 函數(shù)模板重載
// maximum of two int values: int max (int a, int b) {return b < a ? a : b; }// maximum of two values of any type: template<typename T> T max (T a, T b) {return b < a ? a : b; }int main() {::max(7, 42); // calls the nontemplate for two ints::max(7.0, 42.0); // calls max<double> (by argument deduction)::max('a', 'b'); // calls max<char> (by argument deduction)::max<>(7, 42); // calls max<int> (by argument deduction)::max<double>(7, 42); // calls max<double> (no argument deduction)::max('a', 42.7); // calls the nontemplate for two ints }總之,確保只有一個(gè)函數(shù)匹配
#include <cstring> #include <string>// maximum of two values of any type: template<typename T> T max (T a, T b) {return b < a ? a : b; }// maximum of two pointers: template<typename T> T* max (T* a, T* b) {return *b < *a ? a : b; }// maximum of two C-strings: char const* max (char const* a, char const* b) {return std::strcmp(b,a) < 0 ? a : b; }int main () {int a = 7;int b = 42;auto m1 = ::max(a,b); // max() for two values of type intstd::string s1 = "hey";std::string s2 = "you";auto m2 = ::max(s1,s2); // max() for two values of type std::stringint* p1 = &b;int* p2 = &a;auto m3 = ::max(p1,p2); // max() for two pointerschar const* x = "hello";char const* y = "world";auto m4 = ::max(x,y); // max() for two C-strings }如果用傳引用實(shí)現(xiàn)模板,再用傳值重載 C 字符串版本,不能用三個(gè)實(shí)參版本計(jì)算三個(gè) C 字符串的最大值
#include <cstring>// maximum of two values of any type (call-by-reference) template<typename T> T const& max (T const& a, T const& b) {return b < a ? a : b; }// maximum of two C-strings (call-by-value) char const* max (char const* a, char const* b) {return std::strcmp(b,a) < 0 ? a : b; }// maximum of three values of any type (call-by-reference) template<typename T> T const& max (T const& a, T const& b, T const& c) {return max (max(a,b), c); // error if max(a,b) uses call-by-value }int main () {auto m1 = ::max(7, 42, 68); // OKchar const* s1 = "frederic";char const* s2 = "anica";char const* s3 = "lucas";auto m2 = ::max(s1, s2, s3); // run-time ERROR }錯(cuò)誤原因是 max(max(a, b), c) 中,max(a, b) 產(chǎn)生了一個(gè)臨時(shí)對(duì)象的引用,這個(gè)引用在計(jì)算完就馬上失效了
重載版本必須在函數(shù)調(diào)用前聲明才可見(jiàn)
第一章結(jié)束
**我所有的學(xué)習(xí)筆記都在Github倉(cāng)庫(kù)里:https://github.com/fanxing-6/CPP-learning-notes **
,如果訪問(wèn)Github有問(wèn)題也可以訪問(wèn)Gitee:CPP-learning-notes: C++學(xué)習(xí)筆記 (gitee.com)
本人能力有限,筆記難免有疏漏,如果有錯(cuò)誤,歡迎各位關(guān)注公眾號(hào)與我交流,一定會(huì)及時(shí)回復(fù)
Applies lvalue-to-rvalue, array-to-pointer, and function-to-pointer implicit conversions to the type T, removes cv-qualifiers, and defines the resulting type as the member typedef type. Formally:If T names the type "array of U" or "reference to array of U", the member typedef type is U*.Otherwise, if T is a function type F or a reference thereto, the member typedef type is std::add_pointer::type.Otherwise, the member typedef type is std::remove_cv<std::remove_reference::type>::type.These conversions model the type conversion applied to all function arguments when passed by value.The behavior of a program that adds specializations for decay is undefined. ?? ??
總結(jié)
以上是生活随笔為你收集整理的函数模板(参考《C++ Templates 英文版第二版》)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux软件装错了,Linux安装软件
- 下一篇: python xml添加命名空间_XML