當前位置:
首頁 > 科技 > 看完這 7 條,模擬 C+新功能只是一個小目標!

看完這 7 條,模擬 C+新功能只是一個小目標!

你是否希望,在生產代碼中,擁有更高版本的C ++?今天很多C ++開發人員,用的編譯器,都不支持最新版本的標準。

其中可能有很多原因,也許你或你的客戶,有很多遺留代碼需要移植,也許你的硬體,沒有足夠的基礎設施。

關鍵在於,語言提供的最新功能,並不能給大家帶來好處,而且很遺憾的是,其中一些功能,肯定會讓代碼更具表現力。

但是,即使你無法使用這些功能,也不一定要放棄它們的好處。至少不用放棄全部。 有一些方法可以使用代碼中新功能的思路,更準確地傳達你的意圖。

當然,這些方法肯定不如使用新版本C++本身的功能那麼好,這就是你還是需要更新編譯器的原因。 但與此同時,我將介紹7種方法來模擬這些功能,以最低的成本改進你的代碼。

= default, = delete

在C++ 11中,= default可以向編譯器發出指令生成以下內容之一:

?一個默認的構造函數;

?一個拷貝構造函數;

?一個拷貝賦值運算符;

?一個移動構造函數;

?一個移動賦值運算符;

?一個析構函數。

在某些情況下,編譯器無論如何都會生成這些函數。但是對於C++ 11,一些開發人員喜歡在他們的界面中表現這一點,以向讀者保證他們知道這些方法是自動生成的,並且這也是他們想要的類。

在C++ 11之前沒有辦法用原生的方法表現這一點。但你照樣可以在注釋中註明:

類似地,為了阻止編譯器生成這些函數,在C++ 11之前我們不得不將它們聲明為private,並且不實現它們:

在C++ 11中,我們可以將它們聲明為public,並通過「= delete」禁止編譯器生成這些函數。

在C++ 11之前,我們需要更加明確,不僅需要聲明為private,還需要設置「= delete」(但不是真的設置,只是加註釋):

標準演算法

實用的STL演算法庫隨著新版本C++的出現而不斷發展,不斷加入新演算法。其中一些演算法非常泛用。例如copy_if,或all_of,以及其類似的any_of和none_of。

聽起來令人驚訝,但在C++ 11之前它們並不是標準演算法。

但是在C++ 11之前的代碼庫中訪問它們的方法非常簡單:只需去某個參考網站(例如cppreference.com)上複製它們的實現方法(copy_if的實現:https://en.cppreference.com/w/cpp/algorithm/copy;all_of及其類似的演算法的實現:https://en.cppreference.com/w/cpp/algorithm/all_any_none_of),然後把實現方法粘貼到你的代碼就可以了。整個操作大約需要10秒鐘,通過在代碼中使用它們可以節省更多時間。

屬性

屬性是方括弧之間的關鍵字:[[example_attribute]]。它們是C++ 11中引入的,在C++ 17中更多屬性被加了進來。對於屬性的深入分析,你可以參照Bartek的文章《詳解C++ 17:屬性》(https://www.bfilipek.com/2017/07/cpp17-in-details-attributes.html),但屬性的一般概念是你可以將它們當作代碼中的標記,用以向閱讀代碼的人和編譯器表達你的意圖。

我們以[[fallthrough]]屬性為例。這個屬性可以在switch語句中使用,假設你故意沒有在其中一個case中加break,那麼為了執行如下case代碼:

注意這裡的case Value2沒有break。這不免讓人擔心會出bug。大多數情況下它就是個bug,除非你想同時執行case Value2和其他case語句。如下所示,[[fallthrough]]可以更明確地表達這一點:

它可以防止編譯器報錯,也可以向其他開發人員表明:你在寫這段代碼的時候,知道自己在幹什麼。

在C++ 17之前,如果你想利用這個技巧來省略break的話,那麼儘管依然會收到警告,但是至少你可以通過[[fallthrough]]向其他開發者表明你的意圖:

C++ 11和C++ 17的其他屬性也有類似的功能。

概念

概念是C++非常令人期待的特性,它通常應該屬於C++ 20的一部分。概念本質上是模板的介面。概念允許編寫比typename更精確的東西來定義模板參數。實際上,typename僅表示「這是一種類型」,卻並沒有說明該類型的任何其他內容。

像Iterator這樣的概念應該替換模板代碼中操作迭代器的typename,而且Iterator應該被定義為擁有特定的操作(遞增,解引用等)。傳遞沒有這些特定操作的類型將會造成編譯錯誤,併產生明確的錯誤消息,以解釋為什麼該類型不是預期的Iterator。

我不打算想你介紹如何在C++語言引入這些之前,自行模擬概念。這是一個非常棘手的事情,如果你想了解實現方法,那麼可以看看range-v3(https://github.com/ericniebler/range-v3),它使用非常先進的技術來模擬這個功能。

我建議你用更容易方法:謹慎選擇模板參數名稱,並儘可能使用概念的名稱。即使你無法在擁有概念之前替換typename,但是你依然有很大的自由來選擇類型參數的名稱。

以在為Iterator示例時,不要把將模板參數命名為typename命名為T或typename I,而是命名為使用typename Iterator。我們永遠不會因為某個變數是int而叫它int i,但對於模板類型,面對模板類型時我們會更傾向於這麼做。

模板類型的名稱在模板代碼中到處都是,所以讓我們給它取一個好名字,並使用正在開發的概念的標準名稱。當C++(以及我們的代碼庫)實際引入概念時,良好的命名可以讓我們的代碼非常妥帖。

範圍演算法

STL是一個很棒的庫,但有個東西用起來有點麻煩:迭代器。實際上,每個STL都接受兩個迭代器,以定義演算法需要操作的輸入範圍。

當你需要將演算法應用在範圍的一部分上時,這個功能很有用,但如果要遍歷整個範圍(絕大多數情況下如此),迭代器就很礙事了:

如果能將範圍作為整體傳遞就會方便許多:

這就是有關範圍的提案在C++ 20里的目標(同時還有許多其他功能)。但這個功能即使在C++ 98中也很容易模擬,只需要將調用STL演算法的語句包裹在一個接受範圍的函數中即可:

模擬標準組件的函數庫

與上面包裹演算法的函數相比,一些標準庫組件更難實現,因此在代碼中模擬需要更多的工作。

比如std::optional,或std::variant,這兩者出現在C++ 17中。如果你沒有C++ 17,那麼想要編寫自己的實現並可靠地替換標準庫的介面並通過完整的測試,並不是件容易的事情。

幸運的是,我們不需要自己這麼干,因為有人幫你做好了。

僅次於標註庫的就是Boost。它實現了一些組件,包括Optional、Variant以及一些更先進的STL演算法。但是,要注意Boost庫的介面可能會煙花,因為Boost更關注於壓榨語言本身的能力,而不是盡一切可能保持向後兼容。

而且,一些標準庫與Boost中的相應部分有這不小的區別。例如,boost::optional接受引用類型,但std::optional不接受。所以std::optional並不能在任何情況下無縫替換boost::optional。

其他函數庫也在C++ 11上提供C++ 17的標準組件,如Google的Abseil(https://abseil.io/)。Abseil的網站聲稱,「Google開發了許多抽象,許多都與C++ 14、C++ 17以及後續版本的功能一致,或者類似。使用Abseil版的抽象可以讓你立即體驗這些新功能,即使你的代碼還沒準備好享受C++ 11後的世界。」

在其源代碼中,我們確實能看到一些組件會在標準庫函數存在的情況下解析成它們的別名(https://github.com/abseil/abseil-cpp/blob/master/absl/types/optional.h#L48)。

元類

從時間上來看這也許是最古老的提案,但也是C++社區中最流行的提案。元類(Metaclass,https://www.fluentcpp.com/2017/08/04/metaclasses-cpp-summary/)允許在編譯時定義類,在struct和class之外進一步擴展了類型定義的手段。

該提案的一個標準里子就是interface元類,允許使用interface關鍵字定義介面的方法,而編譯器會考慮寫虛描述符、將方法設置為純虛方法、確保沒有數據或私有成員等問題,簡單來說就是符合介面的一切特徵。

代碼看起來像這樣:

相反,我們現在寫介面的方式如下:

現在沒什麼好辦法模擬元類,但我們可以讓它看起來像是個interface元類,來表明我們的意圖:

這不需要任何代價,但能為下個閱讀代碼的人提示你的意圖。而且對於其他提案中的元類也是如此。

早晚你還是需要升級

以上7條技巧能以最小的代價,可以立即給你帶來現代(甚至後現代)C++的好處。至少,比你現在升級編譯器的代價要小得多。它們還能讓你練習並熟悉C++後續版本的特性。

但這並不意味著你應當淺嘗輒止。這只是現代C++的一點體驗,而C++每三年就會有一次進步。如果不想被時代拋棄,就要升級編譯器,然後再模擬最新的功能,再升級,再模擬……

這是一場與現代代碼的永無止境的競賽,我們需要一起加油。

原文:https://www.fluentcpp.com/2018/08/31/modern-cpp-fake-it-until-you-have-it/

作者:Jonathan Boccara,Murex的C++開發人員。

譯者:彎月,責編:胡巍巍

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 CSDN 的精彩文章:

經過 180 年的訓練,OpenAI在DOTA 2 上完虐人類!
單身稅的時代就要來臨,你還沒有用Python幫你找一個女朋友嗎?

TAG:CSDN |