ETH官方钱包

前往
大廳
主題

C語言列舉(enum)成員的走訪與避免被誤改

Yang | 2024-05-04 13:04:22 | 巴幣 0 | 人氣 102

以前設(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)鍵字sizeofsizeof是C語言中很容易引發(fā)災(zāi)難的關(guān)鍵字,
之後再寫範(fàn)例補(bǔ)充紀(jì)錄
送禮物贊助創(chuàng)作者 !
0
留言

創(chuàng)作回應(yīng)

相關(guān)創(chuàng)作

更多創(chuàng)作