summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2021-05-02 01:37:32 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2021-05-11 13:22:44 +0200
commit2be9e6cc2677df7fe842c1a5980d6e0ffcf98fc9 (patch)
treeb0d9af2d37e4d2cf71a87489975282ad4177e0b5
parentd2759e0e32c613b18123970ac15aa1f71949a5e7 (diff)
downloadqtbase-2be9e6cc2677df7fe842c1a5980d6e0ffcf98fc9.tar.gz
Q_DECLARE_OPERATORS_FOR_FLAGS: also define operator&
Bitwise ANDing an enum and a QFlags should yield identical results as ANDing a QFlags and the enum. This latter operator already existed, so add support for the former. Plus, ANDing two enumerators of a flag type should yield a QFlags, and not a plain int. (Note that an arbitrary amount of bits can be set in the result of such operation, as the enumerators themselves may be masks with more than 1 bit set.) This is slightly source incompatible, as we're changing the return type of operator&. Code that was assigning that result to `int` still works as expected, but code that wanted the value back in a QFlags may have inserted some conversions like: flag = Enum(enumerator & otherFlag); ^--------------------- used to yield int, now QFlags which are now going to break as there's no QFlags->Enum conversion. An earlier attempt of this patch, introduced -- and immediately deprecated -- such a conversion, under the form of explicit operator Enum() const; in order to keep such old code working both before and after this change. The problem is that MSVC has a bug with explicit conversions to enumerations [1], which get accidentally considered when they shouldn't, and thus making a lot of code stop compiling due to (false) ambiguities. So, I'm not adding that operator any more. Note that there's a way to keep code working before and after this change: just use flag = Flags(enumerator & otherFlag); // Flags, not Enum (thanks Edward), which goes through a int -> QFlag -> QFlags conversion, and arguably is the idiomatic way of writing such code; or use flag = otherFlag & enumerator; which, as discussed above, has always returned a QFlags. [1] https://developercommunity2.visualstudio.com/t/explicit-conversion-operator-to-enum-is/1412616 [ChangeLog][Potentially Source-Incompatible Changes][QFlags] Bitwise AND-ing two values of an enum type for which flag operations have been declared now produces a QFlags object. Similarly, AND-ing a value of enum type and one of type QFlags now produces a QFlags object. Before, it produced an integer in both cases. This may introduce a slight incompatibility in user code; it is possible to keep the code working in Qt versions before and after this change by inserting enough conversions to QFlags, and/or by changing expressions such as `enum & flag` to `flag & enum` (the latter has always produced a QFlags object). Change-Id: I6e645c010d3aa677820545b0c25678f1dc9a3295 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r--src/corelib/global/qflags.h4
1 files changed, 4 insertions, 0 deletions
diff --git a/src/corelib/global/qflags.h b/src/corelib/global/qflags.h
index 0b7f3f7d6c..2396a8b2fe 100644
--- a/src/corelib/global/qflags.h
+++ b/src/corelib/global/qflags.h
@@ -172,6 +172,10 @@ constexpr inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::
{ return QFlags<Flags::enum_type>(f1) | f2; } \
constexpr inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept \
{ return f2 | f1; } \
+constexpr inline QFlags<Flags::enum_type> operator&(Flags::enum_type f1, Flags::enum_type f2) noexcept \
+{ return QFlags<Flags::enum_type>(f1) & f2; } \
+constexpr inline QFlags<Flags::enum_type> operator&(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept \
+{ return f2 & f1; } \
constexpr inline void operator+(Flags::enum_type f1, Flags::enum_type f2) noexcept = delete; \
constexpr inline void operator+(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept = delete; \
constexpr inline void operator+(int f1, QFlags<Flags::enum_type> f2) noexcept = delete; \