亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

您正在使用C ++中的哪個Typesafe枚舉?

您正在使用C ++中的哪個Typesafe枚舉?

慕工程0101907 2019-10-25 15:10:05
眾所周知,C ++中的內置枚舉不是類型安全的。我想知道在那里使用了哪些實現類型安全枚舉的類……我本人使用以下“自行車”,但是它有些冗長和有限:typesafeenum.h:struct TypesafeEnum{// Construction:public:    TypesafeEnum(): id (next_id++), name("") {}    TypesafeEnum(const std::string& n): id(next_id++), name(n) {}// Operations:public:    bool operator == (const TypesafeEnum& right) const;    bool operator != (const TypesafeEnum& right) const;    bool operator < (const TypesafeEnum& right) const;    std::string to_string() const { return name; }// Implementation:private:    static int next_id;    int id;    std::string name;};typesafeenum.cpp:int TypesafeEnum::next_id = 1;bool TypesafeEnum::operator== (const TypesafeEnum& right) const { return id == right.id; }bool TypesafeEnum::operator!= (const TypesafeEnum& right) const { return !operator== (right); }bool TypesafeEnum::operator< (const TypesafeEnum& right) const  { return id < right.id; }用法:class Dialog { ...    struct Result: public TypesafeEnum    {        static const Result CANCEL("Cancel");        static const Result OK("Ok");    };    Result doModal(); ...};const Dialog::Result Dialog::Result::OK;const Dialog::Result Dialog::Result::CANCEL;另外: 我認為我應該更具體地說明這些要求。我將嘗試總結一下:優先級1:毫無例外,將枚舉變量設置為無效值應該是不可能的(編譯時錯誤)。優先級2:應該可以通過單個顯式函數/方法調用將枚舉值與int轉換。優先級3:盡可能緊湊,優雅,方便的聲明和使用優先級4:將枚舉值與字符串進行相互轉換。優先級5 :(很高興)迭代枚舉值的可能性。
查看完整描述

3 回答

?
德瑪西亞99

TA貢獻1770條經驗 獲得超3個贊

一個不錯的折衷方法是這樣的:


struct Flintstones {

   enum E {

      Fred,

      Barney,

      Wilma

   };

};


Flintstones::E fred = Flintstones::Fred;

Flintstones::E barney = Flintstones::Barney;

從版本上來說,它不是類型安全的,但是用法比標準枚舉更好,并且在需要時仍可以利用整數轉換。


查看完整回答
反對 回復 2019-10-25
?
千萬里不及你

TA貢獻1784條經驗 獲得超9個贊

我個人使用的是typesafe枚舉用法的改編版本。它沒有提供您在編輯中陳述的所有五個“要求”,但無論如何我還是非常不同意其中的一些。例如,我看不到Prio#4(將值轉換為字符串)與類型安全有何關系。無論如何,大多數時間字符串表示形式的單個值都應與類型的定義分開(考慮一下i18n的簡單原因)。Prio#5(迭代,它是可選的)是我想看到的枚舉中自然發生的最好的事情之一,因此令您感到遺憾的是,它在您的請求中顯示為“可選”,但似乎可以通過以下方式更好地解決一個單獨的迭代系統,例如begin/end 函數或enum_iterator,這使它們可與STL和C ++ 11 foreach無縫協作。


OTOH這個簡單的成語很好地提供了Prio#3 Prio#1,這是因為它實際上只會包裝enum帶有更多類型信息的。更不用說這是一個非常簡單的解決方案,在很大程度上不需要任何外部依賴標頭,因此很容易攜帶。它還具有使枚舉范圍為a-la-C ++ 11的優點:


// This doesn't compile, and if it did it wouldn't work anyway

enum colors { salmon, .... };

enum fishes { salmon, .... };


// This, however, works seamlessly.

struct colors_def { enum type { salmon, .... }; };

struct fishes_def { enum type { salmon, .... }; };


typedef typesafe_enum<colors_def> colors;

typedef typesafe_enum<fishes_def> fishes;

解決方案提供的唯一“漏洞”是,它無法解決無法阻止enum將不同類型的s(或an enum和int)直接進行比較的事實,因為直接使用值時會強制執行隱式轉換至int:


if (colors::salmon == fishes::salmon) { .../* Ooops! */... }

但是到目前為止,我發現可以通過簡單地與編譯器進行更好的比較來解決這些問題,例如,顯式提供一個可以比較任意兩種不同enum類型的運算符,然后強制其失敗:


// I'm using backports of C++11 utilities like static_assert and enable_if

template <typename Enum1, typename Enum2>

typename enable_if< (is_enum<Enum1>::value && is_enum<Enum2>::value) && (false == is_same<Enum1,Enum2>::value) , bool >

::type operator== (Enum1, Enum2) {

    static_assert (false, "Comparing enumerations of different types!");

}

盡管到目前為止似乎還沒有破壞代碼,并且確實可以不處理其他問題而明確地處理特定問題,但是我不確定這是“ 應該 ”做的事情(我懷疑它會干擾enum已參與其他地方聲明的轉換運算符;我很樂意收到對此的評論)。


將此與上面的類型安全習慣相結合,就可以enum class在操作性(可讀性和可維護性)方面相對接近C ++ 11 ,而不必做任何過于晦澀的事情。而且我不得不承認這樣做很有趣,我從沒想過要問編譯器是否在處理enums ...


查看完整回答
反對 回復 2019-10-25
  • 3 回答
  • 0 關注
  • 677 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號