成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

一、C++11新特性:auto類型推導(dǎo)

gityuan / 2109人閱讀

摘要:宋體關(guān)鍵字中的含義宋體不再是一個(gè)存儲(chǔ)類型指示符如為純粹類型指示符,而是一個(gè)新的類型指示符等是類型指示符來指示編譯器,聲明變量的類型必須由編譯器在編譯時(shí)期推導(dǎo)而得。


一、auto類型推導(dǎo)

聲明:該筆記是在學(xué)習(xí)《深入理解C++11》、《C++11/14高級(jí)編程 Boost程序庫探秘》時(shí)做的總結(jié),方便以后鞏固復(fù)習(xí)!

1.1、靜態(tài)類型、動(dòng)態(tài)類型和類型推導(dǎo)

靜態(tài)類型:C/C++常被成為靜態(tài)類型的語言,變量必須被定義;

動(dòng)態(tài)類型:python、Perl、JavaScript語言常被稱為動(dòng)態(tài)類型的語言,變量不需要聲明就可以被使用。

靜態(tài)類型和動(dòng)態(tài)類型的區(qū)別:是在對(duì)變量進(jìn)行類型檢測的時(shí)間點(diǎn);靜態(tài)類型的類型檢測主要發(fā)生在編譯階段;動(dòng)態(tài)類型的類型檢測主要發(fā)生在運(yùn)行階段。

動(dòng)態(tài)類型語言變量“拿來就用”的特性依賴的是類型推導(dǎo)技術(shù);事實(shí)上類型推導(dǎo)也可以用于靜態(tài)類型的語言;C++11中類型推導(dǎo)的實(shí)現(xiàn)方式就有兩種:①、auto,②、decltype;先學(xué)習(xí)auto關(guān)鍵字!

auto關(guān)鍵字在早期的C/C++標(biāo)準(zhǔn)中的含義:

按照C/C++早期標(biāo)準(zhǔn),聲明時(shí)使用auto修飾的變量,是具有自動(dòng)存儲(chǔ)的局部變量;幾乎無人使用這種含義,因?yàn)橐话愫瘮?shù)內(nèi)沒有聲明為static的變量總是具有自動(dòng)存儲(chǔ)的局部變量。

auto關(guān)鍵字C++11中的含義:

auto不再是一個(gè)存儲(chǔ)類型指示符(如static、extern為純粹類型指示符),而是一個(gè)新的類型指示符(int、float等是類型指示符)來指示編譯器,
auto聲明變量的類型必須由編譯器在編譯時(shí)期推導(dǎo)而得。

int main(){	double foo();	auto x = 1; //x的類型為int	auto y = foo(); //y的類型為double	struct m 	{		int i;	}str; 	auto str1 = str;//str1的類型是sturct m	auto z;//無法推導(dǎo),不能通過編譯}

auto 聲明的變量必須被初始化,以使編譯能夠從其初始化表達(dá)式中推導(dǎo)出其類型。這里可以理解為auto并非一種“類型”,而是一個(gè)類型聲明時(shí)的“占位符”,編譯器在編譯時(shí)會(huì)將auto替代為變量實(shí)際的類型。

1.2、auto的優(yōu)勢

①、最大優(yōu)勢就是在擁有初始化表達(dá)式的復(fù)雜類型變量聲明時(shí)簡化代碼

由于C++的發(fā)展,聲明變量類型也變得越來越復(fù)雜,很多時(shí)候,名字空間、模板成為了類型的一部分,導(dǎo)致程序員在使用庫的時(shí)候如履薄冰。

#include #incldue <vector>void loopover(std::vector<std:string> & vs){	std::vector<std::string>::iterator i = vs.begin(); //可看出在在不使用u命名空間時(shí),使用iterator 需要書寫大量代碼	for(; i < vs.end(); i++)	{		...	}}

用auto的話,代碼會(huì)的可讀性可以成倍增長

#include #incldue <vector>void loopover(std::vector<std:string> & vs){	std::vector<std::string>::iterator i = vs.begin(); 	//使用auto,就不需要書寫大量代碼	for(auto  i = vs.begin(); i < vs.end(); i++)	{		...	}}

②、第二個(gè)優(yōu)勢則在于可以免除程序員在一些類型聲明時(shí)的麻煩,或者避免一些在類型聲明時(shí)的錯(cuò)誤

在C/C++中,存在著很多隱式或者用戶自定義的類型轉(zhuǎn)換規(guī)則(比如整型與字符型進(jìn)行加法運(yùn)算后,表達(dá)式返回的是整型,這是一條隱式規(guī)則)。這些規(guī)則并非很容易記憶,尤其是在用戶自定義了很多操作符之后。而這個(gè)時(shí)候,auto就有用武之地了。

class PI{    public:    	double operator* (float v)        {            return (double)val * v;        }    	const float val = 3.1415927f;};int main(){    float radius = 1.7e10;    PI pi;    auto circumference = 2 * (pi * radius);    cout << "circumference = " << circumference << endl;    return 0;}
輸出:circumference = 1.06814e+11

這里定義了float型的變量radius(半徑)以及一個(gè)自定義類型PI變量pi(π值),在計(jì)算圓周長的時(shí)候,使用了auto類型來定義變量circumference。這里,PI在與float類型數(shù)據(jù)相乘時(shí),其返回值為double。而PI的定義可能是在其他的地方(頭文件里),main函數(shù)的程序員可能不知道PI的作者為了避免數(shù)據(jù)上溢或者精度降低而返回了double類型的浮點(diǎn)數(shù)。因此main函數(shù)程序員如果使用float類型聲明circumference,就可能享受不了PI作者細(xì)心設(shè)計(jì)帶來的好處。反之,將circumference聲明為auto,則毫無問題,因?yàn)榫幾g器已經(jīng)自動(dòng)地做了最好的選擇。

③、第三個(gè)優(yōu)點(diǎn)就是其“自適應(yīng)”性能夠在一定程度上支持泛型的編程

我們?cè)倩氐缴厦娲a例子,這里假設(shè)改動(dòng)了PI的定義,如將operator*返回值變?yōu)閘ong double,此時(shí),main函數(shù)并不需要修改,因?yàn)閍uto會(huì)“自適應(yīng)”新的類型。

同時(shí),對(duì)于不同的平臺(tái)上的代碼維護(hù),auto也會(huì)帶來一些“泛型”的好處。這里我們以strlen函數(shù)為例,在32位的編譯環(huán)境下,strlen返回的為一個(gè)4字節(jié)的整型,而在64位的編譯環(huán)境下,strlen會(huì)返回一個(gè)8字節(jié)的整型。雖然系統(tǒng)庫為其提供了size_t類型來支持多平臺(tái)間的代碼共享支持,但是使用auto關(guān)鍵字我們同樣可以達(dá)到代碼跨平臺(tái)的效果。

auto v = strlen("hello world!")

由于size_t的適用范圍往往局限于中定義的函數(shù),auto的適用范圍明顯更為廣泛。

當(dāng)auto應(yīng)用于模板的定義中,其“自適應(yīng)”性會(huì)得到更加充分的體現(xiàn)。如:

#include using namespace std;template<typename T1, typename T2>double Sum(T1 & t1, T2 & t2){    auto s = t1 + t2;    return s;}int main(){    int a = 3;    long b = 5;    float c = 1.0f, d = 2.3f;    auto e = Sum<int,long>(a,b);//s的類型被推導(dǎo)為long    auto f = Sum<float,float>(c,d);//s的類型被推導(dǎo)為float	cout << e << endl;	cout << f << endl;	return 0;}
輸出:83.3

在上面程序中,由于類型T1、T2要在模板實(shí)例化時(shí)才能確定,所以在Sum中將變量s的類型聲明為auto的。在函數(shù)main中我們將模板實(shí)例化時(shí),Sum中的s變量會(huì)被推導(dǎo)為long類型,而Sum中的s變量則會(huì)被推導(dǎo)為float。可以看到,auto與模板一起使用時(shí),其“自適應(yīng)”特性能夠加強(qiáng)C++中“泛型”的能力。不過在這個(gè)例子中,由于總是返回double類型的數(shù)據(jù),所以Sum模板函數(shù)的適用范圍還是受到了一定的限制。

④、在宏定義中,避免出現(xiàn)性能問題

#include using namespace std;#define MAX1(a, b) ((a) > (b)) ? (a) : (b)#define MAX2(a, b) ({/        auto _a = (a);/        auto _b = (b);/        (_a > _b) ? _a : _b;})         int main() { 	int m1 = MAX1(1*2*3*4, 5+6+7+8); 	int m2 = MAX2(1*2*3*4, 5+6+7+8); 	cout << m1 << endl; 	cout << m2 << endl;	return 0;  }

定義了兩種類型的宏MAX1和MAX2。兩者作用相同,都是求a和b中較大者并返回。前者采用傳統(tǒng)的三元運(yùn)算符表達(dá)式,這可能會(huì)帶來一定的性能問題。因?yàn)閍或者b在三元運(yùn)算符中都出現(xiàn)了兩次,那么無論是取a還是取b,其中之一都會(huì)被運(yùn)算兩次。而在MAX2中,我們將a和b都先算出來,再使用三元運(yùn)算符進(jìn)行比較,就不會(huì)存在這樣的問題了。

在傳統(tǒng)的C++98標(biāo)準(zhǔn)中,由于a和b的類型無法獲得,所以我們無法定義MAX2這樣高性能的宏。而新的標(biāo)準(zhǔn)中的auto則提供了這種可行性。

1.3、auto使用時(shí)注意事項(xiàng)

①、auto類型指示符與指針和引用之間的關(guān)系

int x = 1;int * y = &x;double foo();int & bar();auto * a = &x; // int*auto & b = x;// int&auto c = y;// int*auto * d = y; // int*//auto * e = &foo();//編譯失敗,指針不能指向一個(gè)臨時(shí)變量//auto & f = foo();//編譯失敗,nonconst的左值引用不能和一個(gè)臨時(shí)變量綁定auto g = bar();// intauto & h = bar();// int&

變量a、c、d的類型都是指針類型,且都指向變量x。實(shí)際上對(duì)于a、c、d三個(gè)變量而言,聲明其為auto *或auto并沒有區(qū)別。

而如果要使得auto聲明的變量是另一個(gè)變量的引用,則必須使用auto &,如同本例中的變量b和h一樣。

②、auto與volatile和const之間也存在著一些相互的聯(lián)系

volatile和const代表了變量的兩種不同的屬性:易變的和常量的。

在C++標(biāo)準(zhǔn)中,它們常常被一起叫作cv限制符(cv-qualifier)。鑒于cv限制符的特殊性,C++11標(biāo)準(zhǔn)規(guī)定auto可以與cv限制符一起使用,不過聲明為auto的變量并不能從其初始化表達(dá)式中“帶走”cv限制符。

double foo();float * bar();const auto a = foo(); //a:const doubleconst auto & b = foo(); //b:const double&volatile auto * c = bar(); //c:volatile float*auto d = a; //d:doubleauto & e = e; //e:const double &auto f = c; //f:float *volatile auto & g = c; //g:volatile float * &

可以看出通過非cv限制的類型初始化一個(gè)cv限制的類型,如變量a、b、c所示。不過通過auto聲明的變量d、f卻無法帶走a和f的常量性或者易失性。這里的例外還是引用,可以看出,聲明為引用的變量e、g都保持了其引用的對(duì)象相同的屬性(事實(shí)上,指針也是一樣的)。

③、auto可以用來聲明多個(gè)變量的類型,不過這些變量的類型必須相同

如果這些變量的類型不相同,編譯器則會(huì)報(bào)錯(cuò)。事實(shí)上,用auto來聲明多個(gè)變量類型時(shí),只有第一個(gè)變量用于auto的類型推導(dǎo),然后推導(dǎo)出來的數(shù)據(jù)類型被作用于其他的變量。

auto x = 1, y = 2;//m是一個(gè)指向const int類型變量的指針,n是一個(gè)int類型的變量const auto* m = &x, n = 1;//auto i = 1, j = 3.14f; //編譯失敗auto o = 1,&p = o,*q = &p; //從左向右推導(dǎo)

使用auto聲明了兩個(gè)類型相同變量x和y,并用逗號(hào)進(jìn)行分隔,這可以通過編譯。而在聲明變量i和j的時(shí)候,按照我們所說的第一變量用于推導(dǎo)類型的規(guī)則,那么由于x所推導(dǎo)出的類型是int,那么對(duì)于變量j而言,其聲明就變成了int j =3.14f,這無疑會(huì)導(dǎo)致精度的損失。而對(duì)于變量m和n,就變得非常有趣,這里似乎是auto被替換成了int,所以m是一個(gè)int *指針類型,而n只是一個(gè)int類型。同樣的情況也發(fā)生在變量o、p、q上,這里o是一個(gè)類型為int的變量,p是o的引用,而q是p的指針。auto的類型推導(dǎo)按照從左往右,且類似于字面替換的方式進(jìn)行。事實(shí)上,標(biāo)準(zhǔn)里稱auto是一個(gè)將要推導(dǎo)出的類型的“占位符”(placeholder)。這樣的規(guī)則無疑是直觀而讓人略感意外的。當(dāng)然,為了不必要的繁瑣記憶,程序員可以選擇每一個(gè)auto變量的聲明寫成一行(有些觀點(diǎn)也認(rèn)為這是好的編程規(guī)范)。

④、只要能夠進(jìn)行推導(dǎo)的地方,C++11都為auto指定了詳細(xì)的規(guī)則,保證編譯器能夠正確地推導(dǎo)出變量的類型

包括C++11新引入的初始化列表,以及new,都可以使用auto關(guān)鍵字

 #include  auto x = 1; auto x1(1); auto y {1};      // 使用初始化列表的auto      	auto z = new auto(1);    // 可以用于new       

auto變量y的初始化使用了初始化列表,編譯器可以保證y的類型推導(dǎo)為int。而z指針?biāo)赶虻亩炎兞吭诜峙鋾r(shí)依然選擇讓編譯器對(duì)類型進(jìn)行推導(dǎo),同樣的,編譯器也能夠保證這種方式下類型推導(dǎo)的正確性。

⑤、不過auto也不是萬能的,受制于語法的二義性,或者是實(shí)現(xiàn)的困難性,auto往往也會(huì)有使用上的限制

  #include         using namespace std;        //void fun(auto x =1){}  // 1: auto函數(shù)參數(shù),無法通過編譯  struct str{  	//auto var = 10;    // 2: auto非靜態(tài)成員變量,無法通過編譯    };  int main() {  char x[3];  auto y = x; // auto z[3] = x; // 3: auto數(shù)組,無法通過編譯    // 4: auto模板參數(shù)(實(shí)例化時(shí)),無法通過編譯  vector<auto> v = {1};  }  

①、對(duì)于函數(shù)fun來說,auto不能是其形參類型??赡茏x者感覺對(duì)于fun來說,由于其有默認(rèn)參數(shù),所以應(yīng)該推導(dǎo)fun形參x的類型為int型。但事實(shí)卻無法符合大家的想象。因?yàn)閍uto是不能做形參的類型的。如果程序員需要泛型的參數(shù),還是需要求助于模板。

②、對(duì)于結(jié)構(gòu)體來說,非靜態(tài)成員變量的類型不能是auto的。同樣的,由于var定義了初始值,讀者可能認(rèn)為auto可以推導(dǎo)str成員var的類型為int的。但編譯器阻止auto對(duì)結(jié)構(gòu)體中的非靜態(tài)成員進(jìn)行推導(dǎo),即使成員擁有初始值。

③、聲明auto數(shù)組。我們可以看到,main中的x是一個(gè)數(shù)組,y的類型是可以推導(dǎo)的,而聲明auto z[3]這樣的數(shù)組同樣會(huì)被編譯器禁止。

④、在實(shí)例化模板的時(shí)候使用auto作為模板參數(shù),如main中我們聲明的vector v。雖然讀者可能認(rèn)為這里一眼而知是int類型,但編譯器卻阻止了編譯。

歡迎關(guān)注公眾號(hào):Kevin的嵌入式學(xué)習(xí)站

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/123196.html

相關(guān)文章

  • 四、C++11特性:追蹤返回類型

    摘要:四追蹤返回類型宋體聲明該筆記是在學(xué)習(xí)深入理解高級(jí)編程程序庫探秘時(shí)做的總結(jié),方便以后鞏固復(fù)習(xí)引入追蹤返回類型的目的宋體追蹤返回類型配合與會(huì)真正釋放中泛型編程的能力簡化函數(shù)的定義,提高代碼的可讀性。 ...

    tianyu 評(píng)論0 收藏0
  • C++入門篇(2)之引用,內(nèi)聯(lián)函數(shù),auto和范圍遍歷

    文章目錄 前言extern C引用1.概念2.語法3.引用特性4.常量引用5.引用做函數(shù)返回值6.引用注意點(diǎn)7.傳值、傳引用效率比較 內(nèi)聯(lián)函數(shù)1.概念2.特性 auto關(guān)鍵字1.概念2.auto的使用細(xì)則3.auto不能推導(dǎo)的場景 基于范圍的for循環(huán)(C++11)使用條件 指針空值nullptr 前言 承接上文入門篇1,博主這次將會(huì)繼續(xù)更新以下內(nèi)容:extern ,引用 ,內(nèi)聯(lián), a...

    wangtdgoodluck 評(píng)論0 收藏0
  • C++】C++快速入門

    摘要:中包含的即為命名空間的成員。使用輸入輸出更方便,不需增加數(shù)據(jù)格式控制,比如整形,字符可以連續(xù)輸出,表示換行缺省參數(shù)備胎,就是給汽車準(zhǔn)備一個(gè)備用輪胎,一旦那個(gè)輪子爆胎或者出了問題,備用輪胎就方便及時(shí)地取而代之,汽車就不至于中途拋錨。 ...

    TalkingData 評(píng)論0 收藏0
  • [初識(shí)C++] 何為最:心酸歷史

    摘要:上面需要了解的是這倆個(gè)版本都是破蛹成蝶的版本世界挑戰(zhàn)榜咋才前三還沒擠進(jìn)去呀,你想想世界上有幾千中編程語言,在其中脫穎出來,可以說是天之嬌子,鳳毛麟角了。支持正版圖靈上面買吧,如果沒錢買盜版吧學(xué)完以后買本正版支持一下,創(chuàng)作不易是吧 ...

    forrest23 評(píng)論0 收藏0
  • Python學(xué)習(xí)之路21-序列構(gòu)成的數(shù)組

    摘要:第行把具名元組以的形式返回。對(duì)序列使用和通常號(hào)兩側(cè)的序列由相同類型的數(shù)據(jù)所構(gòu)成當(dāng)然不同類型的也可以相加,返回一個(gè)新序列。從上面的結(jié)果可以看出,它雖拋出了異常,但仍完成了操作查看字節(jié)碼并不難,而且它對(duì)我們了解代碼背后的運(yùn)行機(jī)制很有幫助。 《流暢的Python》筆記。接下來的三篇都是關(guān)于Python的數(shù)據(jù)結(jié)構(gòu),本篇主要是Python中的各序列類型 1. 內(nèi)置序列類型概覽 Python標(biāo)準(zhǔn)庫...

    ralap 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

gityuan

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<