tft每日頭條

 > 圖文

 > c7數據流

c7數據流

圖文 更新时间:2024-08-08 00:35:05

作者:taoklin,騰訊WXG後台開發

一、簡單特性1. namespace 嵌套

c 17使我們可以更加簡潔使用命名空間:

c7數據流(看完就會用的C17特性總結)1

2. std::variant 升級版的C語言Union

在C 17之前,通常使用Union來定義一個可以存儲不同類型的變量,現在可以通過std::variant<T1,T2,...> 來定義一個可以存儲不同類型的新變量。

std::variant優勢在于:①存儲了變量的類型信息,更安全;②可以存儲複雜對象,更好用。

用法如下

c7數據流(看完就會用的C17特性總結)2

3. [[fallthrough]] 顯式說明某個switch分支無需break

如果在寫代碼時遇到在swtich語句中需要執行完case 1,繼續執行case 2的情況,可以使用[[fallthrough]],此時編譯器會忽略此處break語句檢查,還能顯式的告知Code Reviewer 此處是有意不寫break語句。

用法如下:

c7數據流(看完就會用的C17特性總結)3

4. [[nodiscard]] 顯式說明不能忽略函數返回值

如果我們編寫的某個函數不希望調用時忽略它的返回值,那麼可以在函數聲明處,使用[[nodiscard]]修飾這個函數。

用法如下:

c7數據流(看完就會用的C17特性總結)4

二、std::optional 更優雅地編寫可能無返回結果的函數用法:

使用std::optional<T>來修飾函數返回值,表明這個函數可能不會返回值,T代表原有的返回類型。具體使用方法見示例函數TestOptionalInt:

c7數據流(看完就會用的C17特性總結)5

用途:

過去當我們編寫一個獲取目标值的函數時,如果這個函數在某些情況下不能返回目标值,那麼我們就必須通過兩個參數去獲得目标值:一個參數來表明是否存在目标值,另一個參數返回目标值;或者是在函數無返回值時抛出異常。下面以FindUserName函數來展示C 17之前的幾種實現途徑。

c7數據流(看完就會用的C17特性總結)6

引入C 17的std::optional<T>,我們可以更優雅更安全的編寫FindUserName函數。

c7數據流(看完就會用的C17特性總結)7

三、std::string_view 字符串視圖用法:

C 17引入的std::string_view來協助程序員更高效的使用隻讀字符串,初始化std::string_view時需要傳入已有的字符串。作為函數參數時隻使用值拷貝形式,即std::string_view;不要引用字符串視圖,即:std::string_view&。

std::string_view本質上是持有一個字符串的指針,因此需要保證:①被持有的字符串生命周期比std::string_view變量長;②被持有的字符串在std::string_view變量生命周期結束之前,保持不變。

用途:

當遇到需要使用隻讀字符串,尤其是傳入隻讀字符串作為函數參數時,優先使用std::string_view。在以下兩個場景使用string_view比使用 const string&更好。

适用場景1:可能傳入隻讀C風格字符串參數時

C風格字符串是指: const char* str = "C風格字符串"

char* str = "C風格字符串"

char[] str_array = "C風格字符串"

以一個字符串打印函數StringDisplay為例,下面的代碼是常規的編寫方法。

c7數據流(看完就會用的C17特性總結)8

如果我們在函數中使用const std::string&類型的輸入參數,當我們傳入C風格字符串時,那麼首先要生成一個string對象,此時帶來了額外的拷貝操作。如果我們要避免這樣的情況發生,那麼我們就必須把入參設置為const char*類型,但是這是C風格字符串類型,調用此類函數是很麻煩的,如下所示:

c7數據流(看完就會用的C17特性總結)9

但如果我們使用std::string_view,那麼這些問題都可以解決,如下面的代碼所示:

c7數據流(看完就會用的C17特性總結)10

适用場景2:要進行string.substr()操作時:

對字符串進行處理是一個很常見的業務場景,如果我們需要從字符串中提取某些字段,使用std::string_view是一個非常好的選擇。

以一個字符串分割函數StringSplit為例,下面代碼是常規編寫方法:

c7數據流(看完就會用的C17特性總結)11

在上述代碼中,每分割完一次字符串,都需要把已經分割完的部分去掉,但是我們不能改變原字符串,因此隻能拷貝一個新的字符串傳入下一次遞歸中。但是如果使用字符串視圖:std::string_view,那麼可以改變字符串視圖然後傳入下一次遞歸中,因為改變字符串視圖是不會改變原字符串的,從而避免一次了字符串拷貝,代碼示例如下:

c7數據流(看完就會用的C17特性總結)12

不适用場景:函數内部要調用C風格字符串為參數的子函數

std::string_view 并不是完美的,大部分時候,我們都可以使用std::string_view 替代const std::string&,我們可以把std::string_view理解成,一種同時擁有C語言的const char*的指針拷貝成本和 C 語言中std::string類大部分api的類型。但與std::string相比,std::string_view不提供c_str()函數,因為std::string_view具有以下缺點:

c7數據流(看完就會用的C17特性總結)13

四、if constexpr:按條件編譯用法:

if constexpr語句是編譯期的if判斷語句,if constexpr要求後面的判斷條件是一個編譯期可以确定的常量。

用途:

用于編寫需要進行編譯期判斷的函數,簡化模版函數的書寫。

适用場景1:簡化模版偏特化的寫法

編寫模版函數時,有時需要對某些類型進行特殊處理,此時就需要寫模闆偏特化函數。比如下列代碼展示的Convert函數的例子:

c7數據流(看完就會用的C17特性總結)14

在C 17裡面,可以直接簡化成一個函數:

c7數據流(看完就會用的C17特性總結)15

适用場景2:編寫變參模版函數

在C 17之前,如果要編寫一個變參模闆函數,那麼必須額外寫一個函數處理入參數量最少時候的特例,下面以Sum函數為例:

在C 17中,可以這樣編寫:

c7數據流(看完就會用的C17特性總結)16

使用場景3:替代enable_if

編寫模闆函數時,經常要使用enable_if語句來進行靜态類型檢查,保證模闆輸入的類型滿足某種要求,例如在下列的判斷一個數是奇數還是偶數的IsOdd函數中,該函數通過enable_if語句限定了輸入類型隻能是整數。

c7數據流(看完就會用的C17特性總結)17

使用C 17可以使用更易懂的方法實現編譯期類型檢查:

c7數據流(看完就會用的C17特性總結)18

錯誤用法:

if constexpr語句中,不能将else分支移到判斷語句外面,例如下列的判斷是不是整數的Convert函數的編寫方法就是錯誤的。

c7數據流(看完就會用的C17特性總結)19

五、if及switch初始化語句用法:

c 17支持在if和switch的判斷語句之前增加一個初始化語句,可以用來初始化作用域僅為if或switch語句内的變量,有助于提升代碼的可讀性和正确性。

用途:
    • 當遇到需要在if語句前,聲明一個臨時變量用于這個if語句塊中,且僅僅用于該if語句塊内,可以使用if和switch初始化語句提升代碼可讀性。
    • 在使用lock/iterator等涉及并發/RAII的類型變量時,更好的保證程序正确性。
适用場景:

c7數據流(看完就會用的C17特性總結)20

六、結構化綁定用法:
    • 值拷貝方式綁定:

auto [key, value] = std::make_pair<int, std::string>(1, "名字");

    • 左值引用方式綁定:

auto& [key, value] = std::make_pair<int, std::string>(1, "名字");

    • 右值引用方式綁定,支持移動語意:

auto&& [key, value] = std::make_pair<int, std::string>(1, "名字");

用途:
    • 綁定結構體和類(隻能綁定當前類型的數據,父類或子類數據都不能綁定,并且類内成員變量全都為public屬性)
    • 綁定原生數組
    • 綁定std::pair、std::tuple和std::array
七、其他特性

以下特性僅做記錄,個人觀點不是非常推薦使用。

1.構造函類型推導:模闆類初始化可以不顯示指定類型

在C 17之前,模版類的構造函數在調用時必須指明類型,不能進行隐式類型推導;但是調用普通模版函數時是可以不顯式指明類型的,這是因為普通模闆函數可以進行隐式類型推導,下面代碼以pair、tuple和vector為例展示了這一現象:

c7數據流(看完就會用的C17特性總結)21

在C 17之後,模闆類的構造函數也可以進行隐式類型推導:

c7數據流(看完就會用的C17特性總結)22

個人觀點:構造函數中進行隐式類型推導,這會讓人擔憂可能存在難以發現的類型推導錯誤。下面的例子裡,程序員原意是新建一個std::pair<int, std::string>類型,但是編譯器自動推導出的是std::pair<int, const char*>類型。

c7數據流(看完就會用的C17特性總結)23

這段代碼最後會輸出error type。以上代碼是筆者使用CLion編譯器時的截圖,但是如果使用筆者常用的Vs Code編輯器,并不能像使用CLion實時獲知int_string_pair_a和int_string_pair_c這兩個變量的隐式類型推導結果與程序員原意不符。

2. std::any 可以存任意可拷貝類型變量的容器

C 17使用了std::any來替代C語言中的void*,std::any有以下優點

      • 存儲類型信息,更安全。std::any_cast是一種安全的類型轉換。
      • 像STL容器一樣,析構時會自動析構容器内的對象。

用法如下所示:

c7數據流(看完就會用的C17特性總結)24

個人觀點:使用std::any變量,意味着可能存在動态類型識别,這讓人沒有安全感。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved