電子產(chǎn)業(yè)一站式賦能平臺(tái)

PCB聯(lián)盟網(wǎng)

搜索
查看: 14|回復(fù): 0
收起左側(cè)

從 C++17、C++20 到 C++23,不斷進(jìn)階的枚舉類!

[復(fù)制鏈接]

303

主題

303

帖子

1721

積分

三級(jí)會(huì)員

Rank: 3Rank: 3

積分
1721
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2024-9-10 09:01:00 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
本文經(jīng)授權(quán)轉(zhuǎn)自公眾號(hào)CSDN(ID:CSDNnews)
作者 | Bart?omiej Filipek
隨著 C++ 標(biāo)準(zhǔn)的不斷演進(jìn),枚舉類型(enum class)作為一種重要的數(shù)據(jù)結(jié)構(gòu),在 C++ 社區(qū)中扮演著越來越重要的角色。從 C++17 到 C++23,我們見證了枚舉類型的多項(xiàng)改進(jìn)和完善,這些變化不僅增強(qiáng)了語言本身的表達(dá)能力,也為開發(fā)者提供了更強(qiáng)大、更安全的編程工具。
原文鏈接:https://www.cppstories.com/2024/enum-improvements/

C++語言的演進(jìn)不斷帶來強(qiáng)大的新特性,提升了代碼的安全性、可讀性和可維護(hù)性。在這些改進(jìn)中,我們見證了從 C++17、C++20 到 C++23 中對(duì) enum class 功能的修改和擴(kuò)展。在這篇文章中,我們將探討這些進(jìn)展,重點(diǎn)介紹 C++17 中的初始化改進(jìn)、C++20 中引入的 using enum 關(guān)鍵字,以及 C++23 中的 std::to_underlying 實(shí)用工具。
1、enum class 簡(jiǎn)介
在深入了解這些改進(jìn)之前,讓我們先簡(jiǎn)要回顧一下 enum class 是什么。enum class(限定作用域的枚舉)提供了一種類型安全的方式來定義一組命名常量。與傳統(tǒng)的(無作用域)枚舉不同,enum class 不會(huì)隱式轉(zhuǎn)換為整數(shù)或其他類型,從而防止了意外的誤用。下面是一個(gè)基本示例:
  • #include
    enum class Color {    Red,    Green,    Blue};
    int main() {        Color color = Color::Red;
        if (color == Color::Red)        std::cout "The color is red.
    ";
        color = Color::Blue;
        if (color == Color::Blue)        std::cout "The color is blue.
    ";
        // std::cout     // int i = color;      // error: cannot convert}注意,在 main 函數(shù)的末尾有兩行代碼。由于沒有隱式轉(zhuǎn)換為整數(shù)類型,因此會(huì)出現(xiàn)編譯器錯(cuò)誤。
    作為對(duì)比,下面是一個(gè)類似的例子,但使用的是無作用域枚舉:
  • #include
    enum Color {    Red,    Green,    Blue};
    int main() {        Color color = Red;
        if (color == Red)        std::cout "The color is red.
    ";
        color = Blue;
        if (color == Blue)        std::cout "The color is blue.
    ";
        std::cout // fine, prints integer value!    int i = color;      // fine, can convert...}簡(jiǎn)而言之,enum class 為所有枚舉值提供了單獨(dú)的作用域,同時(shí)也加強(qiáng)了類型安全。沒有隱式的整數(shù)轉(zhuǎn)換,這樣你就能更好地控制設(shè)計(jì)。
    以上的基礎(chǔ)部分很簡(jiǎn)單,接下來讓我們來看看最新 C++ 版本中的一些實(shí)用改進(jìn)。

    2、C++17:使用大括號(hào)初始化基礎(chǔ)類型
    有時(shí)候,enum class 可能顯得過于限制,某些情況下的轉(zhuǎn)換可能會(huì)很方便。
    在 C++17 中,P0138 提案被接受,以下是其中的一個(gè)示例:
  • enum class Handle : uint32_t { Invalid = 0 }; Handle h { 42 }; // OK簡(jiǎn)而言之,當(dāng)你使用 enum class 來定義強(qiáng)類型時(shí),允許從基礎(chǔ)類型進(jìn)行初始化而不產(chǎn)生任何錯(cuò)誤——這在 C++17 之前是無法實(shí)現(xiàn)的。
    這個(gè)變化仍能確保枚舉仍然是安全的,因?yàn)樗鼈冎荒苡糜诮y(tǒng)一/大括號(hào)初始化。請(qǐng)看看下面的代碼:
  • #include
    enum class Handle : uint32_t { Invalid = 0 };
    void process(Handle h) {
    }
    int main() {        Handle h { 42 }; // OK
        // process({10}); // error    process(Handle{10});}你不能直接將 {10} 作為 process 函數(shù)的參數(shù),仍需要明確指定類型。
    在 C++14 中,你可以使用 process(static_cast(10));——如你所見,C++17 版本的改進(jìn)要好得多。

    3、C++20:使用 using enum
    C++20 引入了 using enum 語法,這個(gè)特性允許你將一個(gè)枚舉的所有枚舉值引入當(dāng)前作用域,同時(shí)不失去作用域枚舉的優(yōu)點(diǎn)。請(qǐng)看下面的示例:
  • enum class ComputeStatus {    Ok,    Error,    FileError,    NotEnoughMemory,    TimeExceeded,    Unknown};在早期的 C++ 版本中,使用這些枚舉值時(shí),需要使用枚舉類的名稱進(jìn)行限定:
  • ComputeStatus s = ComputeStatus::NotEnoughMemory;C++20 通過 using enum 聲明簡(jiǎn)化了這一點(diǎn):
  • int main() {    using enum ComputeStatus;    ComputeStatus s = NotEnoughMemory;}上面的簡(jiǎn)單代碼可能沒什么實(shí)際意義,但看看下面這個(gè)例子:
  • int main() {        ComputeStatus s = ComputeStatus::Ok;    switch (s) {        case ComputeStatus::Ok:             std::cout "ok"; break;        case ComputeStatus::Error:             std::cout "Error"; break;        case ComputeStatus::FileError:             std::cout "FileError"; break;        case ComputeStatus::NotEnoughMemory:             std::cout "NotEnoughMemory"; break;        case ComputeStatus::TimeExceeded:             std::cout "Time..."; break;        default: std::cout "unknown...";    }}我們可以將其轉(zhuǎn)換為如下形式:
  • int main() {        ComputeStatus s = ComputeStatus::Ok;    switch (s) {        using enum ComputeStatus;  //         case Ok:             std::cout "ok"; break;        case Error:             std::cout "Error"; break;        case FileError:             std::cout "FileError"; break;        case NotEnoughMemory:             std::cout "NotEnoughMemory"; break;        case TimeExceeded:             std::cout "Time..."; break;        default: std::cout "unknown...";    }}或者,也可以看看下面這個(gè)例子:
  • struct ComputeEngine {    enum class ComputeStatus {        Ok,        Error,        FileError,        NotEnoughMemory,        TimeExceeded,        Unknown    };    using enum ComputeStatus;};
    int main() {        ComputeEngine::ComputeStatus s = ComputeEngine::Ok;}你可以將所有枚舉值引入 ComputeEngine 的作用域中,同時(shí)享受 enum class 帶來的類型安全特性。
    C++20 的這一改進(jìn)使代碼更加簡(jiǎn)潔,并減少了冗余,尤其是在某個(gè)作用域內(nèi)頻繁使用多個(gè)枚舉值的情況下。它提供了一種更加流暢和可讀的方式,同時(shí)不犧牲作用域枚舉所提供的類型安全性。

    4、C++23:std::to_underlying
    C++23 通過引入 std::to_underlying 進(jìn)一步增強(qiáng)了 enum class 的可用性,這個(gè)實(shí)用函數(shù)可以將枚舉值轉(zhuǎn)換為其基礎(chǔ)的整型類型,這個(gè)特性解決了將枚舉值轉(zhuǎn)換為整數(shù)以用于存儲(chǔ)、比較或與其他期望整型的 API 交互的常見需求。
    這個(gè)想法最早出現(xiàn)在 Scott Meyers 的經(jīng)典著作《Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14》一書中。終于在 C++23 中,我們可以享受到這個(gè)被標(biāo)準(zhǔn)化的功能。
    在 C++23 之前,將枚舉轉(zhuǎn)換為其基礎(chǔ)類型需要顯式的類型轉(zhuǎn)換:
  • enum class Permissions : uint8_t {    Execute = 1,  Write = 2,    Read = 4};
    uint8_t value = static_castuint8_t>(Permissions::Read);而有了 std::to_underlying,這個(gè)轉(zhuǎn)換變得更加直接和清晰:
  • #include
    int main() {    Permissions p = Permissions::Read;    auto value = std::to_underlying(p); // C++23}std::to_underlying 函數(shù)提高了代碼的可讀性,并減少了與類型轉(zhuǎn)換相關(guān)的樣板代碼。它還明確了意圖,使得人們能一目了然地知道這是在獲取枚舉的基礎(chǔ)值。

    5、未來的改進(jìn)
    接下來,一個(gè)即將到來的重要更新可能是支持 C++26 反射——可查看提案 P2996(雖然這個(gè)提案還未被接受,但預(yù)計(jì)很快就會(huì)獲得批準(zhǔn))。反射帶來了許多激動(dòng)人心的可能性,比如將枚舉轉(zhuǎn)換為字符串的能力。
    請(qǐng)看提案中的這個(gè)例子:
  • template typename E>  requires std::is_enum_vconstexpr std::string enum_to_string(E value) {  template for (constexpr auto e : std::meta::enumerators_of(^E)) {    if (value == [:e:]) {      return std::string(std::meta::name_of(e));    }  }  return "";}
    enum Color { red, green, blue };static_assert(enum_to_string(Color::red) == "red");static_assert(enum_to_string(Color(42)) == "");當(dāng)然,你也可以不必等到 C++26,依賴第三方庫就能體驗(yàn)這個(gè)功能,如 Neargye/magic_enum @GitHub。   
    本文轉(zhuǎn)自公眾號(hào)“CSDN”,ID:CSDNnews分享個(gè)群友推薦的招聘類小程序這里分享一個(gè)交流群群友推薦的招聘小程序,其中有很多二三線城市,比如赤峰、保定、阿克蘇之類的三四線城市,還支持按照崗位、地點(diǎn)和薪資要求來找合適的崗位。
    經(jīng)常遇到一些想回老家或者二三線城市的同學(xué)苦于沒有合適的去處,打開boss直聘和獵聘網(wǎng)這些招聘類軟件,結(jié)果發(fā)現(xiàn)好的崗位基本都集中在一線城市,很少看到那種有二三線城市的招聘崗位。
  • 發(fā)表回復(fù)

    本版積分規(guī)則


    聯(lián)系客服 關(guān)注微信 下載APP 返回頂部 返回列表