類型推導(dǎo):函數(shù)模板與auto

從函數(shù)模板談起

函數(shù)模板的類型推導(dǎo)機制是在C++98時代就有的务冕,auto的類型推導(dǎo)機制與其基本一致墓阀,所以先理解函數(shù)模板類型推倒
函數(shù)模板可以用如下代碼框架表示:

#template<typename T>
void f(PT param);

f(expr);

PT與T的不同之處在于PT相對于T可能有一些飾詞(adornments)主届,如const和引用&。
對于模板類型T的推導(dǎo)是PT和expr共同作用的結(jié)果轩娶。下面分幾種情況討論類型推導(dǎo)的原則:

1)PT是一般的引用或指針

原則:

  • expr是一個引用(指針)類型暗甥,忽略其引用(指針)部分
  • expr其他部分去匹配PT得到T的類型。(匹配原則就是如果PT有const則expr的const忽略焚廊,PT無const,expr有冶匹,則添加)

代碼示例如下

//PT是指針或引用類型,expr的引用或指針被忽略 
//PT是T& 
#template<typename T>
void f(T& param);
int x = 11;
const int cx = x;
const int& rx = x;
f(x);  //PT是int&咆瘟, T是int 
f(cx); //PT是const int&嚼隘, T是const int 
f(rx); //PT是const int&, T是const int 


//PT是const T&袒餐,expr中的const被忽略 
#template<typename T>
void f(const T& param);
int x = 11;
const int cx = x;
const int& rx = x;
f(x);  //PT是int&飞蛹, T是int 
f(cx); //PT是const int&须肆, T是int 
f(rx); //PT是const int&, T是int 

//PT是T*桩皿, 
#template<typename T>
void f(T* param);
int x = 11;
const int* px = &x;
f(&x);  //PT是int*豌汇, T是int 
f(px); //PT是const int*, T是const int

總結(jié)如下:


推導(dǎo)總結(jié).png

2)PT是萬能引用(universal reference, ie &&)

注:萬能引用既不是左值引用也不是右值引用泄隔,而是遇左則左拒贱,遇右則右。
原則:

  • 如果expr是左值引用佛嬉,則PT和T均被推導(dǎo)為左值引用(這是所有情況中T被推導(dǎo)為引用的唯一情況)逻澳;
  • 如果expr是右值引用,則與1)情況類似暖呕,即引用被忽略斜做,其余部分去匹配PT。

代碼示例如下:

//PT是T&&湾揽,左值推導(dǎo)為左值引用瓤逼,右值引用忽略 
#template<typename T>
void f(T&& param);
int x = 11;
const int cx = x;
const int& rx = x;
f(x);  //x是左值, PT是int&库物, T是int& 
f(cx); //cx是左值霸旗, PT是const int&, T是const int& 
f(rx); //rx是左值戚揭, PT是const int&诱告, T是const int&
f(11); //11是右值, PT是int&&民晒, T是int

結(jié)果總結(jié)如下表格


PT萬能引用推導(dǎo).png

3)PT既不是指針精居,也不是引用

當(dāng)PT既不是指針,又不是引用(也就是只有T時)潜必,用傳值傳參的方式考慮問題靴姿,可以想清楚推導(dǎo)原則。
所謂傳值傳參(pass by value)意味著拷貝一份新的獨立的對象刮便,但內(nèi)容與原內(nèi)容相同空猜。
所以有如下原則和解釋::

  • expr如果是引用绽慈,則忽略引用部分恨旱;
  • expr的const部分,volatile部分也被忽略坝疼。(傳值傳參拷貝一份新的搜贤,原來是const,不代表新拷貝的就是const)钝凶;
  • expr存在指向常量的指針(ie const int*)應(yīng)保留仪芒。 (指針拷貝了一份新的唁影,但是他指向的內(nèi)容仍然是原來的內(nèi)容,應(yīng)保證那塊內(nèi)容不可變)掂名;

代碼示例如下:

//PT是T 
#template<typename T>
void f(T param);
int x = 11;
const int cx = x;
const int& rx = x;
const char* ptr1 = "C++11";
const char* ptr2 const = "c++14";
f(x);  //PT是int据沈, T是int 
f(cx); //PT是int, T是int 
f(rx); //PT是int饺蔑, T是int 
f(ptr1);//PT是const char*, T是const char* 
f(ptr2);//PT是const char*,T是const char*锌介,指向內(nèi)容保留不可更改,指針本身const被移除猾警。

結(jié)果總結(jié)如下表格


PT既不是指針孔祸,也不是引用.png

補充1)關(guān)于數(shù)組參數(shù)的推導(dǎo)

數(shù)組參數(shù)在c++中可以退化為指針進行傳參,所以補充對數(shù)組參數(shù)的類型推導(dǎo)发皿。
原則:

  • 當(dāng)PT為傳值類型(就是T)時崔慧,推導(dǎo)為退化的指針類型
  • 當(dāng)PT為引用類型(T&)時,推導(dǎo)為帶有數(shù)組大小的明確的數(shù)組類型(如const char[13])穴墅;

代碼示例如下:

//數(shù)組參數(shù) 
const char name[] = "C++11"; 
#template<typename T>
void f(T param);
f(name); //PT為 const char*,T被推導(dǎo)為const char*  

#template<typename T>
void f(T& param);
f(name); //PT為const char (&)[6], T被推導(dǎo)為const char[6]
數(shù)組參數(shù)的推導(dǎo).png

補充2)關(guān)于函數(shù)參數(shù)的推導(dǎo)

函數(shù)在c++中也可以退化為指針惶室,所以函數(shù)參數(shù)的推導(dǎo)和數(shù)組基本一致。
直接看代碼示例:

void someFunc(int, double); //類型void(int, double) 
#template<Typename T>
void f1(T param); 
f1(someFunc); //PT 為void(*) (int, double), T推導(dǎo)為 void(*) (int, double)玄货; 
#template<Typename T>
void f2(T& param);
f2(SomeFunc); //PT為void(&)(int, double)拇涤, T推導(dǎo)為 void(int, double);
函數(shù)參數(shù)的推導(dǎo).png

函數(shù)模板到auto

auto的類型推導(dǎo)機制與函數(shù)模板類型推導(dǎo)機制幾乎完全一樣,除了一個小的注意點誉结。
回顧函數(shù)模板類型推導(dǎo)的代碼框架:

#template<typename T>
void f(PT param);

f(expr);

推導(dǎo)出T鹅士,需要PT與expr的共同作用。
在帶有auto的表達式中惩坑,auto代表的就是T掉盅,也就是最后要推導(dǎo)出的結(jié)果;等號右邊代表expr以舒;而auto與其飾詞一起趾痘,表示的是PT
注意此時最后更關(guān)心的是PT的類型,也就是式中待推導(dǎo)變量的類型蔓钟。如 :

int x = 11永票; 
const auto& rx = x;  //auto代表T, const auto&代表PT, x代表expr 

所以第一部分中討論的函數(shù)模板類型推導(dǎo)原則完全適用于auto的類型推導(dǎo)。
給出代碼示例如下:

auto x = 11; //類型3滥沫, auto推導(dǎo)為int
const auto cx = x; // 類型3, auto推導(dǎo)為int, cx類型為int 
const auto& rx = x; //類型1侣集, auto推導(dǎo)為int, rx類型為int& 
auto&& uref1 = x; //左值,auto推導(dǎo)為int&, uref1類型為int& 
auto&& uref2 = cx; //左值兰绣,auto推導(dǎo)為const int&, uref2類型為const int& 
auto&& uref3 = 11; //右值世分,auto推導(dǎo)為int, uref3類型 int&& 
const char name[] = "C++11" ;
auto arr1 = name; // auto推導(dǎo)為const char*, arr1類型const char* 
auto& arr2 = name; //auto推導(dǎo)為const char[6]缀辩, arr2類型為const char(&)[6] 
void someFunc(int, double);
auto func1 = someFunc(); //auto推導(dǎo)為void(*)(int, double)臭埋, func1類型為void(*)(int, double)
auto& func2 = someFunc();//auto推導(dǎo)為void(int, double)踪央,func2類型為void(&)(int, double)

注:

  1. 上述原則都是與函數(shù)模板推導(dǎo)一直的原則。一點不同在于函數(shù)模板沒有對于{}的推導(dǎo)瓢阴,這是auto獨有的畅蹂。
    使用{}初始化,會被推導(dǎo)為std:initializer_list的相關(guān)類型荣恐。如:
    auto x3 = {27}; //推導(dǎo)為std::initializer_list<int>;
  2. 在函數(shù)返回類型和lambda表達式參數(shù)中使用auto魁莉,使用的是模板參數(shù)類型推導(dǎo),而不是auto的類型推導(dǎo)募胃;
    也就是在此情況下旗唁,推導(dǎo){}會報錯。如:
auto createList() { //error痹束,模板參數(shù)類型推導(dǎo)不能處理{} 
    return {1,2,3};
} 

本文總結(jié)了函數(shù)模板參數(shù)推導(dǎo)检疫,進而推廣到auto的類型推導(dǎo)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末祷嘶,一起剝皮案震驚了整個濱河市屎媳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌论巍,老刑警劉巖烛谊,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘉汰,居然都是意外死亡丹禀,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門鞋怀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來双泪,“玉大人,你說我怎么就攤上這事密似”好” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵残腌,是天一觀的道長村斟。 經(jīng)常有香客問我,道長抛猫,這世上最難降的妖魔是什么蟆盹? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮邑滨,結(jié)果婚禮上日缨,老公的妹妹穿的比我還像新娘。我一直安慰自己掖看,他們只是感情好匣距,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著哎壳,像睡著了一般毅待。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上归榕,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天尸红,我揣著相機與錄音,去河邊找鬼刹泄。 笑死外里,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的特石。 我是一名探鬼主播盅蝗,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼姆蘸!你這毒婦竟也來了墩莫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤逞敷,失蹤者是張志新(化名)和其女友劉穎狂秦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體推捐,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡裂问,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了牛柒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愕秫。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖焰络,靈堂內(nèi)的尸體忽然破棺而出戴甩,到底是詐尸還是另有隱情,我是刑警寧澤闪彼,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布甜孤,位于F島的核電站,受9級特大地震影響畏腕,放射性物質(zhì)發(fā)生泄漏缴川。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一描馅、第九天 我趴在偏房一處隱蔽的房頂上張望把夸。 院中可真熱鬧,春花似錦铭污、人聲如沸恋日。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽岂膳。三九已至誓竿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谈截,已是汗流浹背筷屡。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留簸喂,地道東北人毙死。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像喻鳄,于是被迫代替她去往敵國和親扼倘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345