爭(zhēng)論不斷的C++語言
學(xué)習(xí)C++語言時(shí),發(fā)現(xiàn)C++里面有那么多的tricks,其實(shí)日常編程中要用到的trick少之又少,除非你是庫的設(shè)計(jì)者,否則很多的tricks根本就無需關(guān)注,也許C++在最近的幾年會(huì)漸漸的走向開發(fā)界的***。
讓我們先對(duì)“學(xué)院派”下一個(gè)定義好不好?先問你自己一個(gè)問題,你心目中對(duì)“學(xué)院派”的定義是什么? 以下是一些選項(xiàng): 1. 傾向于理論美。2. 忽視實(shí)際編碼中的constraints(如效率,模塊性、可讀性等等)。
3. 倡導(dǎo)語言律師行為。4. 鉆細(xì)節(jié)。5. … 我想如果我說C++語言設(shè)計(jì)強(qiáng)調(diào)理論美,所有學(xué)過C++的人恐怕都會(huì)笑了…正如Bjarne自己所說的,C++設(shè)計(jì)初期的Rule of Thumb之一便是“不要陷入到對(duì)***性的固執(zhí)追求中”;不過具有諷刺意味的是,后面你會(huì)看到,正是這樣的一種哲學(xué)帶來了今天對(duì)C++的這個(gè)誤解。
我猜持這樣一種觀點(diǎn)的人大多對(duì)于學(xué)院派的定義都是模糊的,一般都介于“提倡鉆語言細(xì)節(jié)并利用語言細(xì)節(jié)的做法”、“關(guān)注語言特性本身而忽略實(shí)際編碼需求”、“對(duì)語言細(xì)節(jié)無休止的爭(zhēng)論”等等之間。
所以,當(dāng)有人說“C++==學(xué)院派”的時(shí)候,他的真實(shí)意思很可能是:“C++語言的陰暗角落太多,而且C++社群還有提倡對(duì)語言角落把握的潛在哲學(xué),就連C++0x的進(jìn)化也似乎更多關(guān)注語言特性,而那些語言特性根本就跟我們實(shí)際開發(fā)者脫節(jié)了…”等等。
首先得承認(rèn)的是,在近一個(gè)十年的時(shí)間內(nèi),C++社群的確某種程度上建立起了一種對(duì)語言細(xì)節(jié)過分關(guān)注的心態(tài),這種心態(tài)毫無疑問是錯(cuò)誤的,但只有知道這個(gè)錯(cuò)誤是如何來的,才能解開這個(gè)結(jié)。
而且,就算一時(shí)解不開這個(gè)結(jié),知道了原因之后才能保持理性的寬容態(tài)度,而不是亂發(fā)抱怨。一個(gè)理性的態(tài)度,更有助于良性發(fā)展。例如如果C++社群都能明白這種潛哲學(xué)從何而來,或許也就會(huì)漸漸走向更好的發(fā)展了。
那C++中就沒有了嗎?有。STL的for_each算法,于是你寫: struct MyOp{void operator()(int& i){…}}; std::for_each(v.begin(), v.end(), MyOp()); 這個(gè)方案實(shí)際很差。一是你還是得寫v.begin()、v.end(),二是你得為此定義一整個(gè)新類。
三是這個(gè)新類并不在你使用這個(gè)新類(for_each被調(diào)用)的點(diǎn)上,因?yàn)榫植款惒荒茏瞿0鍏?shù)。 你要的是lambda function: for_each(v.begin(), v.end(), <>(int& i){ …}); 可是C++98沒有。 你要的是內(nèi)建foreach: for(int& i : v) {…} 可是C++98沒有。
鑒于循環(huán)結(jié)構(gòu)是編程中最常出現(xiàn)的結(jié)構(gòu)之一。這個(gè)問題其實(shí)還是比較惱人的,如果你覺得不惱人可能只是因?yàn)槟氵m應(yīng)性習(xí)慣了,這未必是好事。比如每次都要寫std::vector::iterator就很讓人惱火,如果我換個(gè)容器,就要修改一堆std::vector<…>。那用typedef行不行啊?行。
可仍然還是需要寫一次typedef,我很懶,我什么多余的無用代碼都不想寫。要知道,每多出一行無用的(并非因表達(dá)思想所需要才出現(xiàn))的代碼,就增加一點(diǎn)維護(hù)負(fù)擔(dān),這也正是為什么語言的表達(dá)力如此重要的原因。 那怎么辦?如果我告訴你,C++98里面其實(shí)你也可以寫: foreach(int& i , v){ …} 你怎么想? 廢話。當(dāng)然是求之不得了。有這么簡(jiǎn)潔的表達(dá)方式誰還不想用啊。
我需要告訴你的另一個(gè)事實(shí)是。為了在C++98里面幾近***地實(shí)現(xiàn)這個(gè)特性,有人把標(biāo)準(zhǔn)的角落挖了個(gè)底朝天。不,我不是在為鉆語言細(xì)節(jié)找理由,我只是想告訴你,許多人所認(rèn)為的鉆語言細(xì)節(jié)的做法,其實(shí)一開始大多是由用戶實(shí)際需求驅(qū)動(dòng)的。
這個(gè)foreach設(shè)施被C++程序員們?cè)噲D實(shí)現(xiàn)了N遍N種做法,可見需求之強(qiáng)烈??上Ы^大多數(shù)實(shí)現(xiàn)都遠(yuǎn)遠(yuǎn)稱不上好用,就連現(xiàn)在這個(gè)實(shí)現(xiàn)的作者也早在03年在CUJ上發(fā)了一個(gè)實(shí)現(xiàn),也稱不上好用。
是后來又契而不舍才實(shí)現(xiàn)了最終這個(gè)真正好用的版本的。 我想說的是,上面這個(gè)美好的foreach,當(dāng)然人人都想用。但問題是要在C++98下實(shí)現(xiàn)它只能靠挖標(biāo)準(zhǔn),這是唯一的途徑。#t#
要不然就得等語言進(jìn)化,并忍受若干年,誰愿意?況且這個(gè)foreach設(shè)施還能作占位符,在C++09來臨之前兢兢業(yè)業(yè)履行其職責(zé),C++09加入內(nèi)建foreach支持之后只消用正則表達(dá)式搜索全局替換,就OK了,沒有任何的升級(jí)麻煩。
再舉一個(gè)經(jīng)典的例子:STL里面的traits。其實(shí)traits不應(yīng)該是traits。traits最自然的實(shí)現(xiàn)方式應(yīng)該是C++09的concept。但STL需要用到靜態(tài)dispatch技術(shù)啊,那怎么辦?要么用traits(增加語言復(fù)雜性),要么不用(顯然不行)。再舉個(gè)經(jīng)典的例子:模板元編程。模板元編程有啥用?日常開發(fā)者八輩子估計(jì)也用不到。但真的嗎?沒錯(cuò),日常開發(fā)者并不會(huì)直接用到。
但是,由模板元編程支持的各個(gè)boost子庫呢?被選入C++語言的TR1的各個(gè)子庫呢(間接用到)?那日常開發(fā)者用不用學(xué)模板元編程呢?不用學(xué),根本不用學(xué),這么復(fù)雜的技術(shù)學(xué)什么呢?也就是點(diǎn)技巧上的東西。那為什么偏有人學(xué)呢?待會(huì)再說。 還有大量的例子。
其實(shí)STL的traits技術(shù)已經(jīng)能夠說明問題了。如果你仔細(xì)看一看,你會(huì)發(fā)現(xiàn),那些所謂的利用C++黑暗角落的技術(shù),幾乎無一不是出現(xiàn)在庫開發(fā)里面的,而之所以出現(xiàn)在庫開發(fā)里面,是因?yàn)閹扉_發(fā)中的需求驅(qū)動(dòng)的——為了開發(fā)出更好的庫。難道你不想用更好的庫? 哦,說到“更好的庫”,肯定會(huì)有同學(xué)有意見了。