摘要訊息 : C++ 20 Proposal P1099R5《Using Enum》導讀
不知道大家對於列舉這個東西是什麼感受, 不過對於名稱空間, 我想大家在保證沒有名稱衝突的情況下, 會使用 using namespace
來提升可視範圍. 否則, 在可以保證沒有名稱衝突的情況下, 不斷寫出 std::
和 cv::
等等名稱空間難免讓人感到煩惱. 但是對於列舉, 你沒有任何辦法避免列舉名稱的書寫 :
enum class color {
red, green, blue, white, black
};
string to_string(color c) {
switch(c) {
case color::red :
return "red";
case color::green :
return "green";
case color::blue :
return "blue";
case color::white :
return "white";
default :
return "black";
}
}
在函式 to_string
中, 我們重複了 4 次 color
, 而且這種情況還會隨著列舉中的列舉值增加而變得更加嚴重. 因此在可能的情況下, 有些人會拒絕使用強型別列舉, 而改用弱型別列舉, 他們並不願意多打這麼多字, 哪怕是複製也是比較麻煩的. 除此之外, 列舉和名稱空間非常相似, 列舉值只是不會存儲的帶有 static
、constexpr
和 inline
的 "變數" 罷了, 為什麼就不能像名稱空間一樣直接提升可視範圍呢?
於是, 這篇 Proposal 就提出, 像 using namespace
那樣 using enum
:
using enum ENUM_NAME;
其中, ENUM_NAME
是某一個列舉的名稱. 將這個特性用在函式 to_string
中, 就可以打少很多字 :
enum class color {
red, green, blue, white, black
};
string to_string(color c) {
//using enum color; //放在這裡也可以
switch(c) {
using enum color;
case red :
return "red";
case green :
return "green";
case blue :
return "blue";
case white :
return "white";
default :
return "black";
}
}
對於名稱空間, using
可以做的不只是這些, 你可能還想到我們可以只提升名稱空間中某一個名稱的可視範圍, 對於列舉來說, 當然也可以 :
using enum ENUM_NAME::ENUM_VALUE;
其中, ENUM_NAME
是某一個列舉的名稱, ENUM_VALUE
是位於 ENUM_NAME
中的一個列舉值
列舉名稱是一個型別, 那麼它可以起別名, 那麼如果對某個列舉的別名使用 using
來提升可視範圍, 這也是行得通的, 兩者並不矛盾
我們上面說的都是強型別的列舉, 但是 using
指示對於弱型別的列舉同樣適用 :
struct Foo {
enum E {
A, B, C, D, E, F
};
};
int main(int argc, char *argv[]) {
using Foo::E; //OK
}
這篇 Proposal 還給出了重複宣告的情形. 對於類別來說, 重複宣告是不被允許的 :
enum E {
x
};
struct S {
enum H {
y
};
enum class K {
z
};
using E::x; //OK
using E::x; //Error, 重複宣告
using H::y; //Error, 重複宣告
using K::z; //OK
};
但是對於名稱空間來說, 重複宣告是可以的 :
enum E {
x
};
namespace S {
enum H {
y
};
enum class K {
z
};
using E::x; //OK
using E::x; //OK
using H::y; //OK
using K::z; //OK
};
但是對於弱型別列舉來說, 這並不是新引入的, Proposal 只是在這裡作了一個提醒而已 :
#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 namespace A, B, C; //Error
但是針對列舉來說, 可以使用逗號一次性提升多個列舉值的可視範圍 (這個同樣不是新引入的, 而是原來就有的, Proposal 只是在這裡作一個提示) :
#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
}
當然, 於名稱空間對應, 這篇 Proposal 提出使用 using
指示一次性提升多個列舉的可視範圍是不可行的. 也就是說, 下列程式碼同樣會引發編碼錯誤 :
using enum A, B, C; //Error
最後, 這篇 Proposal 還提出, 使用 using
提升列舉值的可視範圍的時候, 列舉型別並不會被引入 :
enum class E {
x = 2020, y, z
};
struct Foo {
using enum E; //引入了名稱 x, y 和 z, 但是並沒有引入名稱 E
};
自創文章, 原著 : Jonny, 如若需要轉發, 在已經授權的情況下請註明出處 :《【C++ 20 Proposal 導讀】Using Enum》https://jonny.vip/2020/09/05/%e3%80%90cplusplus-20-proposal-%e5%b0%8e%e8%ae%80%e3%80%91using-enum/
Leave a Reply