詳解C++11中的類型推斷
C++11中的類型推斷
C++11中為了更好的支持泛型編程,提供了 auto
和decltype
兩個(gè)關(guān)鍵詞,目的就是提供編譯階段的自動(dòng)類型推導(dǎo)。
1.auto
關(guān)鍵詞的新意義
在C++98中,auto
是一個(gè)類型修飾符,用以顯式聲明自動(dòng)變量(局部變量的),而在C++11中,這一用法已經(jīng)棄用,現(xiàn)在auto
用于聲明變量。
1.1 auto
聲明變量
我們通過幾個(gè)例子看一下,auto
聲明變量時(shí)的規(guī)則。
int x; int *y; double foo(); int& bar(); auto *a=&x;//int * auto &b=x;//int & auto c=y;//int * auto *d=y;//int * auto e=bar();// int auto &f=bar();//int &
1.如果使得auto
聲明的變量是引用類型,必須使用auto &
.
2.如果變量本身是指針類型,則auto *
和auto
是一樣的,這里*
變成冗余符號(hào)
double foo(); float * bar(); const auto a=foo();//const double const auto & b=foo();//const double & volatile auto * const c=bar();//volatile float * const auto d=a;//double auto &e=a;//const double & auto f=c;//volatile float * volatile auto &g=c;//volatile float * &
3.聲明為auto
的變量不能從其初始化表達(dá)式中帶走頂層cv
限定符.
auto i=1,j=1.12f;//編譯錯(cuò)誤
4.auto
可以聲明多個(gè)變量,不過這些變量必須類型相同
1.2 auto
無法推導(dǎo)的情況
#include<vector> using namespace std; void fun(auto x=1){}//錯(cuò)誤 struct str { auto var=10;//錯(cuò)誤 }; int main() { char x[3]; auto y=x; auto z[3]=x;//錯(cuò)誤 vector<auto>V={1,2,3};//錯(cuò)誤 }
auto
不能作為函數(shù)形參(這是模板函數(shù)的事情)類中,auto
不能用來聲明非靜態(tài)成員auto
不能聲明數(shù)組auto
不能用于模板實(shí)參
2.decltype
類型推導(dǎo)
decltype
和auto
都是用來類型推導(dǎo)的,不過 decltype
的功能更加強(qiáng)大 ,下面就是decltype
的簡(jiǎn)單用法
2.1 decltype
的應(yīng)用場(chǎng)景
一種情況是,decltype
和auto
一樣來聲明變量:
#include<typeinfo> #include<iostream> using namespace std; int main() { int i; decltype(i) j=0; cout<<typeid(j).name()<<endl;//i float a; double b; decltype(a+b) c; cout<<typeid(c).name()<<endl;//d }
另一種情況是:typedef
或using
配合使用decltype
using size_t=decltype(sizeof(0)); using ptrdiff_t=decltype((int*)0-(int*)0); using nullptr_t=decltype(nullptr);
順便一提,在C++11中,using
已經(jīng)完美替代typedef
:
#include<iostream> #include<type_traits> #include<string> #include<map> using namespace std; typedef unsigned int UINT; using uint=unsigned int; template<typename T> using Mapstring=map<T,char*>; Mapstring<int> number_string; int main() { cout<<is_same<uint,UINT>::value<<endl;//1 cout<<is_same<map<int,char*>,decltype(number_string)>::value<<endl;//1 }
typedef
能干的事情,using
都能干,但是using
能干的,比如給模板取一個(gè)別名,typedef
做不到
decltype
的另一種功能就是給匿名的結(jié)構(gòu)體或者枚舉推導(dǎo)類型來重用,
enum class {K1,K2,K3} anon_e; decltype(anon_e) as;
2.2 decltype
比auto
更加精確
首先decltype
和auto
最明顯的不同就是,decltype(e)
它和sizeof()
差不多,可以接收一個(gè)參數(shù),不過這里我講的不同是,同一個(gè)變量,使用decltype
和auto
得到的結(jié)果不同。
說直接點(diǎn),decltype
的類型推斷比auto
準(zhǔn)確
const int ic=0; decltype(ic) a;//const int auto b=ic;//int volatile int iv; decltype(iv) c;//volatile int auto d=iv;//int struct S { int i; }; const S cs={0}; decltype(cs.i) e;//int
auto
它不能帶走變量的頂層cv
限定符,而decltype(e)
卻可以帶走e
的cv
限定符,所以說,decltype
的類型推斷更加準(zhǔn)確。還要一點(diǎn)細(xì)節(jié),就是說類本身是用cv
限定符修飾的,而類成員使用decltype
時(shí)確推斷不出來。
我們知道,auto
只能帶走指針類型,卻無法帶走引用類型,而decltype
就可以同時(shí)帶走引用和指針
#include<iostream> #include<type_traits> using namespace std; int main() { int i=1; decltype(i) & var1=i;// int & cout<<is_lvalue_reference<decltype(var1)>::value<<endl;//1 int &j=i; decltype(j) var2=i; decltype(j)& var3=i; cout<<is_same<decltype(j),decltype(j)&>::value<<endl;//1,`&`的冗余 int* p=&i; decltype(p) var4=&i;//int * decltype(p)* var5=&p;//int ** const int k=1; const decltype(k) var6=1;//const int `const`冗余 }
上面這段代碼,信息量很大
首先,decltype(e)
可以帶走e
的引用和指針類型
其次,decltype(e)
會(huì)對(duì)&
和cv
限定符產(chǎn)生冗余,而不會(huì)對(duì)*
產(chǎn)生冗余
最后,如果不確定decltype(e)
的類型,可以使用<type_traits>
頭文件中的一些方法
總之,就是一句話:decltype(e)
能直接返回e
的準(zhǔn)確類型
但是,如果decltype
更加優(yōu)越,那么為什么還要auto
呢?
一種說法是
auto
用法更加簡(jiǎn)單,更重要的原因是,auto
和lambda
函數(shù)的配合使得,C++11相對(duì)于C++98,變得脫胎換骨,我個(gè)人認(rèn)為C++11最重要的就是lambda
函數(shù)。
2.3 decltype
對(duì)于表達(dá)式的推斷
我們知道在decltype(e)
中,e
被要求是一個(gè)表達(dá)式,即expression
,而在上面我們所講的e
通常是一個(gè)名稱,即id_expression
,如果e
是一個(gè)非名稱的表達(dá)式,那么推斷結(jié)果也會(huì)不同
int i; decltype(i) a;//int decltype((i)) b;//int &
在上面例子中,
i
就是一個(gè)id_expression
,而(i)
它不是id_expression
,而是一個(gè)左值表達(dá)式,所以上述推導(dǎo)結(jié)果會(huì)不同。
我們直接來看decltype(e)
的推導(dǎo)細(xì)則
- 如果
e
是id_expression
或者類成員表達(dá)式,decltype(e)
的結(jié)果就是e
本身的類型 - 否則,如果
e
是左值表達(dá)式,設(shè)它的類型是T
,那么decltype(e)
的結(jié)果就是T&
- 否則,如果
e
是將亡值,設(shè)它的類型是T
,那么decltype(e)
的結(jié)果就是T&&
- 否則,如果
e
是純右值,設(shè)它的類型是T
,那么decltype(e)
的結(jié)果就是T
int i=4; int arr[5]={0}; int *ptr=arr; struct S { double d; }s; void foo(int); void foo(double); int && Rref();//函數(shù)返回值是將亡值 const bool Func(int); decltype(arr) var1;//int[5] decltype(ptr) var2;//int * decltype(s.d) var3;//double decltype(foo) var4;//無法通過編譯,foo被重載 decltype(Rref()) var5;//int && decltype(true? i:i) var6;//int& decltype((i)) var7;//int & decltype(++i) var8;//int & decltype(arr[3]) var9;// int & decltype(*ptr) var10;//int & decltype("abc") var11;//const char(&) [4] decltype(1) var12;//int decltype(i++) var13;//int decltype(Func(1)) var14=true;//const bool
3.追蹤返回類型
auto
和decltype
可以進(jìn)行配合使用,來實(shí)現(xiàn)泛型編程中的追蹤返回類型
template<class T1,class T2> decltype(t1+t2) sum(T1& t1,T2& t2) { return (t1+t2); }
上面這段代碼,想法狠簡(jiǎn)單,但是它都無法通過C++11和C++98中的編譯器,因?yàn)榫幾g器是從左往右讀的,讀到
decltype(t1+t2)
時(shí),t1
和t2
沒有聲明,所以無法通過編譯,我們可以通過返回類型后置的方法實(shí)現(xiàn)上述功能
template<typename T1,typename T2> auto sum(T1& t1,T2& t2)->decltype(t1+t2) { return (t1+t2); }
上面就是追蹤返回類型,最終
sum
函數(shù)的返回類型由decltype(t1+t2)
確定,而不是auto
確定,如果我們把->decltype(t1+t2)
去掉,那么最終返回類型就由auto
指定,我們其實(shí)很不希望這樣,因?yàn)?code>auto并不精確,decltype
更加精確。
追蹤返回類型其實(shí)就是返回類型后置,它的還有一種用法就是,提高函數(shù)指針的可讀性:
#include<type_traits> #include<iostream> using namespace std; int (*(*pf())())(){ return nullptr; } auto pf1() ->auto (*)() -> int (*)() { return nullptr; } int main() { cout<<is_same<decltype(pf),decltype(pf1)>::value<<endl;//1 }
上述代碼中,
pf
和pf1
都是函數(shù)指針,其返回的也是一個(gè)函數(shù)指針,該函數(shù)指針又返回一個(gè)函數(shù)指針,不過明顯pf1
的定義方式可讀性更高。
到此這篇關(guān)于C++11中的類型推斷的文章就介紹到這了,更多相關(guān)C++11類型推斷內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中產(chǎn)生臨時(shí)對(duì)象的情況及其解決方案
這篇文章主要介紹了C++中產(chǎn)生臨時(shí)對(duì)象的情況及其解決方案,以值傳遞的方式給函數(shù)傳參,類型轉(zhuǎn)換以及函數(shù)需要返回對(duì)象時(shí),并給對(duì)應(yīng)給出了詳細(xì)的解決方案,通過圖文結(jié)合的方式講解的非常詳細(xì),需要的朋友可以參考下2024-05-05C++之關(guān)于string對(duì)象的大小比較
這篇文章主要介紹了C++之關(guān)于string對(duì)象的大小比較方式,具有很好的 參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11c++ 求數(shù)組最大最小值函數(shù)的實(shí)現(xiàn)
這篇文章主要介紹了c++ 求數(shù)組最大最小值函數(shù)的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07C/C++讀寫JSON數(shù)據(jù)的詳細(xì)過程記錄
JSON文件無論是在web開發(fā)、客戶端開發(fā)、服務(wù)端等開發(fā)中都是應(yīng)用比較廣泛的的第一種輕量級(jí)數(shù)據(jù)交換格式,非常方便閱讀和編寫,下面這篇文章主要給大家介紹了關(guān)于C/C++讀寫JSON數(shù)據(jù)的詳細(xì)過程,需要的朋友可以參考下2023-04-04C語言實(shí)現(xiàn)在windows服務(wù)中新建進(jìn)程的方法
這篇文章主要介紹了C語言實(shí)現(xiàn)在windows服務(wù)中新建進(jìn)程的方法,涉及C語言進(jìn)程操作的相關(guān)技巧,需要的朋友可以參考下2015-06-06從頭學(xué)習(xí)C語言之switch語句和分支嵌套
這篇文章主要為大家詳細(xì)介紹了C語言之switch語句和分支嵌套,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01