簡體   English   中英

安全地將整數與強類型枚舉進行比較

[英]Safely compare integer to strongly typed enum

當積分值可能不在枚舉值范圍內時,如何安全地將未知類型的積分值與強類型枚舉進行比較?

將積分值與枚舉進行比較的最明顯方法是將積分值a轉換為枚舉類型E ,並與枚舉值b進行比較,如下所示:

template <typename I, typename E>
bool compare(I a, E b) { return static_cast<E>(a) == b; }

但是,如果a不在枚舉值的范圍內,則會導致未指定的行為,對於[expr.static.cast] / 10:

可以將整數或枚舉類型的值顯式轉換為枚舉類型。 如果原始值在枚舉值(7.2)的范圍內,則該值不變。 否則, 結果值未指定 (可能不在該范圍內)。

這可以在結果失敗中看出( compare如上):

enum E : uint8_t { A = 0 };
compare(256, E::A); // returns true, 256 == E::A, but E::A = 0

可以將枚舉轉換為整數類型,但如果整數類型不能表示所有枚舉值,則可能導致錯誤的結果:

enum E : int { A = 256 };
template <typename I, typename E>
bool compare(I a, E b) { return a == static_cast<I>(b); }
compare((uint8_t)0); // returns true, 0 == E::A, but E:A = 256

枚舉可以轉換為其底層整數類型,保證能夠表示所有枚舉值。

template <typename I, typename E>
bool compare(I a, E b) { return a == static_cast<std::underlying_type_t<E>>(b); }

如果整數類型和枚舉類型在signededness上不同,那么通常的算術轉換仍然存在問題。

enum class : int32_t { A = -1 };
compare(4294967295u, E3::A); // returns true

這里, E::A = (int32_t)-1被轉換為unsigned int ,它不能表示-1,將其轉換為(最有可能)4294967295。

只有當一個類型是無符號的而另一個類型具有負值(因此必須是有符號類型)時,才會發生整數到另一個不能表示其值的整數類型的轉換。 由於無符號值和負值不可能相等,我們可以告訴比較結果而無需比較確切的值。

template <typename I, typename E>
bool compare(I a, E b) {
    using UTE = std::underlying_type_t<E>; 
    return !(std::is_unsigned_v<I> && static_cast<UTE>(b) < 0) &&
           !(std::is_unsigned_v<UTE> && a < 0) &&
           a == static_cast<UTE>(b);
}

這將正確捕獲案例,如果負值將轉換為無符號值,然后可以匹配另一個操作數。 由於編譯器在編譯時知道類型,它可以將符號檢查表達式優化為空, a<0b<0適合於ab的類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM