詳解C++11中的類型推斷
C++11中的類型推斷
C++11中為了更好的支持泛型編程,提供了 auto
和decltype
兩個關鍵詞,目的就是提供編譯階段的自動類型推導。
1.auto
關鍵詞的新意義
在C++98中,auto
是一個類型修飾符,用以顯式聲明自動變量(局部變量的),而在C++11中,這一用法已經棄用,現(xiàn)在auto
用于聲明變量。
1.1 auto
聲明變量
我們通過幾個例子看一下,auto
聲明變量時的規(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
是一樣的,這里*
變成冗余符號
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
的變量不能從其初始化表達式中帶走頂層cv
限定符.
auto i=1,j=1.12f;//編譯錯誤
4.auto
可以聲明多個變量,不過這些變量必須類型相同
1.2 auto
無法推導的情況
#include<vector> using namespace std; void fun(auto x=1){}//錯誤 struct str { auto var=10;//錯誤 }; int main() { char x[3]; auto y=x; auto z[3]=x;//錯誤 vector<auto>V={1,2,3};//錯誤 }
auto
不能作為函數(shù)形參(這是模板函數(shù)的事情)類中,auto
不能用來聲明非靜態(tài)成員auto
不能聲明數(shù)組auto
不能用于模板實參
2.decltype
類型推導
decltype
和auto
都是用來類型推導的,不過 decltype
的功能更加強大 ,下面就是decltype
的簡單用法
2.1 decltype
的應用場景
一種情況是,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
已經完美替代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
能干的,比如給模板取一個別名,typedef
做不到
decltype
的另一種功能就是給匿名的結構體或者枚舉推導類型來重用,
enum class {K1,K2,K3} anon_e; decltype(anon_e) as;
2.2 decltype
比auto
更加精確
首先decltype
和auto
最明顯的不同就是,decltype(e)
它和sizeof()
差不多,可以接收一個參數(shù),不過這里我講的不同是,同一個變量,使用decltype
和auto
得到的結果不同。
說直接點,decltype
的類型推斷比auto
準確
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
的類型推斷更加準確。還要一點細節(jié),就是說類本身是用cv
限定符修飾的,而類成員使用decltype
時確推斷不出來。
我們知道,auto
只能帶走指針類型,卻無法帶走引用類型,而decltype
就可以同時帶走引用和指針
#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)
會對&
和cv
限定符產生冗余,而不會對*
產生冗余
最后,如果不確定decltype(e)
的類型,可以使用<type_traits>
頭文件中的一些方法
總之,就是一句話:decltype(e)
能直接返回e
的準確類型
但是,如果decltype
更加優(yōu)越,那么為什么還要auto
呢?
一種說法是
auto
用法更加簡單,更重要的原因是,auto
和lambda
函數(shù)的配合使得,C++11相對于C++98,變得脫胎換骨,我個人認為C++11最重要的就是lambda
函數(shù)。
2.3 decltype
對于表達式的推斷
我們知道在decltype(e)
中,e
被要求是一個表達式,即expression
,而在上面我們所講的e
通常是一個名稱,即id_expression
,如果e
是一個非名稱的表達式,那么推斷結果也會不同
int i; decltype(i) a;//int decltype((i)) b;//int &
在上面例子中,
i
就是一個id_expression
,而(i)
它不是id_expression
,而是一個左值表達式,所以上述推導結果會不同。
我們直接來看decltype(e)
的推導細則
- 如果
e
是id_expression
或者類成員表達式,decltype(e)
的結果就是e
本身的類型 - 否則,如果
e
是左值表達式,設它的類型是T
,那么decltype(e)
的結果就是T&
- 否則,如果
e
是將亡值,設它的類型是T
,那么decltype(e)
的結果就是T&&
- 否則,如果
e
是純右值,設它的類型是T
,那么decltype(e)
的結果就是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
可以進行配合使用,來實現(xiàn)泛型編程中的追蹤返回類型
template<class T1,class T2> decltype(t1+t2) sum(T1& t1,T2& t2) { return (t1+t2); }
上面這段代碼,想法狠簡單,但是它都無法通過C++11和C++98中的編譯器,因為編譯器是從左往右讀的,讀到
decltype(t1+t2)
時,t1
和t2
沒有聲明,所以無法通過編譯,我們可以通過返回類型后置的方法實現(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
指定,我們其實很不希望這樣,因為auto
并不精確,decltype
更加精確。
追蹤返回類型其實就是返回類型后置,它的還有一種用法就是,提高函數(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ù)指針,其返回的也是一個函數(shù)指針,該函數(shù)指針又返回一個函數(shù)指針,不過明顯pf1
的定義方式可讀性更高。
到此這篇關于C++11中的類型推斷的文章就介紹到這了,更多相關C++11類型推斷內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
c++ 求數(shù)組最大最小值函數(shù)的實現(xiàn)
這篇文章主要介紹了c++ 求數(shù)組最大最小值函數(shù)的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07