詳解C++11中的類(lèi)型推斷
C++11中的類(lèi)型推斷
C++11中為了更好的支持泛型編程,提供了 auto和decltype兩個(gè)關(guān)鍵詞,目的就是提供編譯階段的自動(dòng)類(lèi)型推導(dǎo)。
1.auto關(guān)鍵詞的新意義
在C++98中,auto是一個(gè)類(lèi)型修飾符,用以顯式聲明自動(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聲明的變量是引用類(lèi)型,必須使用auto &.
2.如果變量本身是指針類(lèi)型,則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ò)這些變量必須類(lèi)型相同
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ù)的事情)類(lèi)中,auto不能用來(lái)聲明非靜態(tài)成員auto不能聲明數(shù)組auto不能用于模板實(shí)參
2.decltype類(lèi)型推導(dǎo)
decltype和auto都是用來(lái)類(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)型來(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的類(lèi)型推斷比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的類(lèi)型推斷更加準(zhǔn)確。還要一點(diǎn)細(xì)節(jié),就是說(shuō)類(lèi)本身是用cv限定符修飾的,而類(lèi)成員使用decltype時(shí)確推斷不出來(lái)。
我們知道,auto只能帶走指針類(lèi)型,卻無(wú)法帶走引用類(lèi)型,而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的引用和指針類(lèi)型
其次,decltype(e)會(huì)對(duì)&和cv限定符產(chǎn)生冗余,而不會(huì)對(duì)*產(chǎn)生冗余
最后,如果不確定decltype(e)的類(lèi)型,可以使用<type_traits>頭文件中的一些方法
總之,就是一句話(huà):decltype(e)能直接返回e的準(zhǔn)確類(lèi)型
但是,如果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è)名稱(chēng),即id_expression,如果e是一個(gè)非名稱(chēng)的表達(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或者類(lèi)成員表達(dá)式,decltype(e)的結(jié)果就是e本身的類(lèi)型 - 否則,如果
e是左值表達(dá)式,設(shè)它的類(lèi)型是T,那么decltype(e)的結(jié)果就是T& - 否則,如果
e是將亡值,設(shè)它的類(lèi)型是T,那么decltype(e)的結(jié)果就是T&& - 否則,如果
e是純右值,設(shè)它的類(lèi)型是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 bool3.追蹤返回類(lèi)型
auto和decltype可以進(jìn)行配合使用,來(lái)實(shí)現(xiàn)泛型編程中的追蹤返回類(lèi)型
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ò)返回類(lèi)型后置的方法實(shí)現(xiàn)上述功能
template<typename T1,typename T2>
auto sum(T1& t1,T2& t2)->decltype(t1+t2)
{
return (t1+t2);
}上面就是追蹤返回類(lèi)型,最終
sum函數(shù)的返回類(lèi)型由decltype(t1+t2)確定,而不是auto確定,如果我們把->decltype(t1+t2)去掉,那么最終返回類(lèi)型就由auto指定,我們其實(shí)很不希望這樣,因?yàn)?code>auto并不精確,decltype更加精確。
追蹤返回類(lèi)型其實(shí)就是返回類(lèi)型后置,它的還有一種用法就是,提高函數(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的定義方式可讀性更高。
到此這篇關(guān)于C++11中的類(lèi)型推斷的文章就介紹到這了,更多相關(guān)C++11類(lèi)型推斷內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解C語(yǔ)言如何執(zhí)行HTTP GET請(qǐng)求
在現(xiàn)代互聯(lián)網(wǎng)時(shí)代,網(wǎng)絡(luò)數(shù)據(jù)的獲取和分析變得越來(lái)越重要,本文我們將使用C語(yǔ)言和libcurl庫(kù)來(lái)編寫(xiě)一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)爬蟲(chóng),以執(zhí)行HTTP GET請(qǐng)求并獲取淘寶網(wǎng)頁(yè)的內(nèi)容,感興趣的可以了解下2023-11-11
基于Matlab實(shí)現(xiàn)野狗優(yōu)化算法的示例代碼
野狗優(yōu)化算法(Dingo?Optimization?Algorithm,?DOA)模仿澳大利亞野狗的社交行為。DOA算法的靈感來(lái)源于野狗的狩獵策略,即迫害攻擊、分組策略和食腐行為。本文將通過(guò)Matlab實(shí)現(xiàn)這一算法,感興趣的可以了解一下2022-04-04
C++ OpenCV實(shí)戰(zhàn)之手寫(xiě)數(shù)字識(shí)別
這篇文章主要為大家詳細(xì)介紹了如何使用machine learning機(jī)器學(xué)習(xí)模塊進(jìn)行手寫(xiě)數(shù)字識(shí)別功能,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-08-08
C++?OpenCV實(shí)戰(zhàn)之零部件的自動(dòng)光學(xué)檢測(cè)
這篇文章主要為大家介紹一個(gè)C++?OpenCV的實(shí)戰(zhàn)——零部件的自動(dòng)光學(xué)檢測(cè),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-09-09
C++實(shí)現(xiàn)LeetCode(172.求階乘末尾零的個(gè)數(shù))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(172.求階乘末尾零的個(gè)數(shù)),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
VC實(shí)現(xiàn)的病毒專(zhuān)殺工具完整實(shí)例
這篇文章主要介紹了VC實(shí)現(xiàn)的病毒專(zhuān)殺工具完整實(shí)例,詳細(xì)講述了針對(duì)病毒的進(jìn)程終止、刪除文件及回復(fù)注冊(cè)表與啟動(dòng)項(xiàng)等,同時(shí)介紹了與之相關(guān)的系統(tǒng)函數(shù),非常具有參考借鑒價(jià)值,需要的朋友可以參考下2014-10-10

