《C++ 學習筆記》中, 我們已經詳細講述過了列舉, 這篇文章是針對《C++ 學習筆記》中的列舉進行補充. 我們已經說過, 列舉分為弱型別和強型別 :

  • 強型別列舉 (enum class) : 進行型別轉化需要借助 static_cast
  • 弱型別列舉 (enum) : 可以隱含地進行型別轉化, 包括整型至浮點數的轉化

在前置宣告的方面, 強型別列舉和弱型別列舉的表現不相同. 強型別列舉支援提前宣告, 但是弱型別列舉不直接支援提前宣告. 在明確標識列舉值的型別之後, 弱型別列舉也可以提前宣告

C++ 11 引入強型別列舉之後, 是否意味著弱型別列舉應該完全被淘汰呢? 答案顯然是否定的. 根據哲學的說法, 萬物存在皆有理. 首先, 弱型別列舉是從 C 語言遺傳的, 如果取消弱型別列舉, 那麼會導致 C++ 和 C 的直接不相容. 下面再舉一個實例, 說明弱型別列舉在 C++ 11 之後仍然有用 :

#include <iostream>

using namespace std;
int main(int argc, char *argv[]) {
    tuple<string /* name */, long /* number */, char /* age */> t {"Jonny", 1, 18};
    enum user_information {
        name, number, age
    };
    cout << get<name>(t) << endl;      //獲取名稱, 等價於 std::get<0>(t)
}

可以看到, 列舉使得 std::tuple 中存儲的信息更加清晰. 但是如果使用強型別列舉 :

#include <iostream>

using namespace std;
int main(int argc, char *argv[]) {
    tuple<string /* name */, long /* number */, char /* age */> t {"Jonny", 1, 18};
    enum class user_information {
        name, number, age
    };
    cout << get<static_cast<int>(user_information::name)>(t) << endl;      //獲取名稱, 等價於 get<0>(t)
}

這樣的程式碼過於複雜, 還不如直接使用 get<0>(t) 來獲取

另外, 在函式樣板中, 如果強型別列舉作為樣板引數, 它的表現可能不如弱型別列舉要好 :

template <typename E>
void f() {
    E e;
    //...
    static_cast<...>(E::some_value);        //向本來應有的型別進行轉型, 但是我們不知道列舉值本來持有什麼樣的型別. 因此, 樣板參數不確定
}

但是, 這也並不是不能解決的, 標頭檔 <type_traits> 中提供了一個工具 std::underlying_tpye 來萃取列舉值原本持有的型別 :

template <typename E>
void f() {
    E e;
    //...
    static_cast<typename underlying_type<E>::type>(E::some_value);
}

最後再增加一個我們從來沒有提到過的知識, 就是使用 using 來提升列舉值的可視範圍 :

#include <iostream>

using namespace std;
enum E {
    x = 2020
};
namespace NS {
    using ::E::x;
}
int main(int argc, char *argv[]) {
    cout << NS::x << endl;      //OK, 輸出 : 2020
}

使用 using 配合逗號, 可以一次性提升多個列舉值的可視範圍 :

#include <iostream>

using namespace std;
enum E {
    x = 2020, y, z
};
namespace NS {
    using ::E::x, ::E::y, ::E::z;
}
int main(int argc, char *argv[]) {
    cout << NS::x << endl;      //輸出 : 2020
    cout << NS::y << endl;      //輸出 : 2021
    cout << NS::z << endl;      //輸出 : 2022
}