網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
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
聲明變量
我們通過(guò)幾個(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è)變量,不過(guò)這些變量必須類型相同
1.2 auto
無(wú)法推導(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
不能用來(lái)聲明非靜態(tài)成員auto
不能聲明數(shù)組auto
不能用于模板實(shí)參
2.decltype
類型推導(dǎo)
decltype
和auto
都是用來(lái)類型推導(dǎo)的,不過(guò) decltype
的功能更加強(qiáng)大 ,下面就是decltype
的簡(jiǎn)單用法
2.1 decltype
的應(yīng)用場(chǎng)景
一種情況是,decltype
和auto
一樣來(lái)聲明變量:
#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)類型來(lái)重用,
enum class {K1,K2,K3} anon_e; decltype(anon_e) as;
2.2 decltype
比auto
更加精確
首先decltype
和auto
最明顯的不同就是,decltype(e)
它和sizeof()
差不多,可以接收一個(gè)參數(shù),不過(guò)這里我講的不同是,同一個(gè)變量,使用decltype
和auto
得到的結(jié)果不同。
說(shuō)直接點(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
限定符,所以說(shuō),decltype
的類型推斷更加準(zhǔn)確。還要一點(diǎn)細(xì)節(jié),就是說(shuō)類本身是用cv
限定符修飾的,而類成員使用decltype
時(shí)確推斷不出來(lái)。
我們知道,auto
只能帶走指針類型,卻無(wú)法帶走引用類型,而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
呢?
一種說(shuō)法是
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ì)不同。
我們直接來(lái)看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;//無(wú)法通過(guò)編譯,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)行配合使用,來(lái)實(shí)現(xiàn)泛型編程中的追蹤返回類型
template<class T1,class T2> decltype(t1+t2) sum(T1& t1,T2& t2) { return (t1+t2); }
上面這段代碼,想法狠簡(jiǎn)單,但是它都無(wú)法通過(guò)C++11和C++98中的編譯器,因?yàn)榫幾g器是從左往右讀的,讀到
decltype(t1+t2)
時(shí),t1
和t2
沒(méi)有聲明,所以無(wú)法通過(guò)編譯,我們可以通過(guò)返回類型后置的方法實(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ù)指針,不過(guò)明顯pf1
的定義方式可讀性更高。
原文鏈接:https://blog.csdn.net/m0_71009069/article/details/128800260
相關(guān)推薦
- 2022-10-18 C++數(shù)據(jù)結(jié)構(gòu)之二叉搜索樹的實(shí)現(xiàn)詳解_C 語(yǔ)言
- 2023-05-23 Django?事務(wù)回滾的具體實(shí)現(xiàn)_python
- 2023-06-16 Pytorch中的?torch.distributions庫(kù)詳解_python
- 2022-12-29 Android?Fragment的具體使用方式詳解_Android
- 2022-08-17 C語(yǔ)言超全面講解字符串函數(shù)_C 語(yǔ)言
- 2022-04-15 C++中構(gòu)造函數(shù)詳解_C 語(yǔ)言
- 2022-08-10 詳細(xì)講解Swift中的類型占位符_Swift
- 2022-07-16 Spring Boot簡(jiǎn)易增刪改查(CRUD)案例
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支