[英]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<0
或b<0
適合於a
和b
的類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.