以前設(shè)計(jì)列舉(enum)時(shí),曾經(jīng)自定義過加法運(yùn)算(operator++),
用來從上一個(gè)列舉成員移動(dòng)到下一個(gè)成員,參考
後來遇到需要旗標(biāo)類型的列舉,像是C#的FlagsAttribute,譬如
很難用加法移動(dòng)或走訪列舉成員
後來發(fā)現(xiàn)C11有std::initializer_list<>,可以利用begin()和end()走訪列舉成員,
還能利用size()知道列舉成員數(shù)量,參考
但可惜initializer_list不能像陣列利用索引子[],取出容器內(nèi)指定的列舉成員
C的列舉也不像C#能直接ToString()轉(zhuǎn)字串,要自行設(shè)計(jì)
團(tuán)隊(duì)開發(fā)或是有甲乙方不同腳色的專案開發(fā),設(shè)計(jì)列舉還要小心,定義好後幾乎不能再做修改,
修改列舉值或字串,或新增或刪除列舉成員,都很容易引發(fā)大災(zāi)難!
以下拿C#的enum FileShare當(dāng)範(fàn)例,嘗試在C語言設(shè)計(jì)FileShare時(shí),要能
1.定義好每個(gè)列舉成員值
2.定義好每個(gè)列舉成員字串
3.走訪列舉成員值或字串(旗標(biāo)類型列舉也沒問題)
4.利用索引子[]取出指定的列舉成員值或字串
5.利用編譯檢查卡死列舉定義,提醒開發(fā)團(tuán)隊(duì)成員,改FileShare要很小心,否則無法編譯
template<typename T, T... Args>
struct CEArray //constexpr類型的陣列容器
{
static constexpr unsigned int TypeSize = sizeof(T);
static constexpr unsigned int Count = (sizeof... (Args));
static constexpr T Data[Count] = {Args...};
};
template<typename T, T... Args>
constexpr T CEArray<T, Args...>::Data[];
class FileShare //旗標(biāo)類型列舉
{
public: //列舉成員值
enum Enum
{
None = 0, //0
Read = None + 1 == 1 ? 1 : throw std::invalid_argument(""), //1
Write = Read + 1 == 1 << 1 ? 1 << 1 : throw std::invalid_argument(""), //2
ReadWrite = (Read | Write) == 3 ? 3 : throw std::invalid_argument(""), //3
Delete = Write + 2 == 1 << 2 ? 1 << 2 : throw std::invalid_argument(""), //4
Inheritable = Delete + 12 == 1 << 4 ? 1 << 4 : throw std::invalid_argument(""), //16
};
public: //列舉成員字串
static constexpr const char (&NoneStr)[sizeof("None")] = "None";
static constexpr const char (&ReadStr)[sizeof("Read")] = "Read";
static constexpr const char (&WriteStr)[sizeof("Write")] = "Write";
static constexpr const char (&ReadWriteStr)[sizeof("ReadWrite")] = "ReadWrite";
static constexpr const char (&DeleteStr)[sizeof("Delete")] = "Delete";
static constexpr const char (&InheritableStr)[sizeof("Inheritable")] = "Inheritable";
public: //陣列容器,用來儲(chǔ)存列舉成員值(AllEnum)和字串(AllEnumStr)
static constexpr CEArray<Enum, None, Read, Write, ReadWrite, Delete, Inheritable> AllEnum {};
static constexpr const char *AllEnumStr[] = {NoneStr, ReadStr, WriteStr, ReadWriteStr, DeleteStr, InheritableStr};
protected: //利用編譯檢查卡死列舉定義
static constexpr bool _unitTestResult1 = Write == 2 && Delete == 4 && Inheritable == 16 ? true : throw std::invalid_argument("");
static constexpr bool _unitTestResult2 = sizeof(AllEnumStr) / sizeof(char *) == AllEnum.Count ? true : throw std::logic_error(""); //sizeof(AllEnumStr) == 48
static constexpr bool _unitTestResult3 = AllEnum.Data[0] == None ? true : throw std::invalid_argument("");
static constexpr bool _unitTestResult4 = AllEnum.Data[AllEnum.Count - 1] == Inheritable ? true : throw std::invalid_argument("");
static constexpr bool _unitTestResult5 = AllEnumStr[0] == NoneStr ? true : throw std::invalid_argument("");
static constexpr bool _unitTestResult6 = AllEnumStr[AllEnum.Count - 1] == InheritableStr ? true : throw std::invalid_argument("");
};
constexpr const char *FileShare::AllEnumStr[];
//走訪列舉成員
for (const auto& fs: FileShare::AllEnum.Data) {}
//或索引取出列舉成員
for (int i = 0; i < FileShare::AllEnum.Count; ++i) {}
//走訪列舉成員字串
for (auto& fsStr: FileShare::AllEnumStr) {}
以上另外標(biāo)記關(guān)鍵字sizeof,sizeof是C語言中很容易引發(fā)災(zāi)難的關(guān)鍵字,
之後再寫範(fàn)例補(bǔ)充紀(jì)錄