diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2021-05-02 01:37:32 +0200 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2021-05-11 13:22:44 +0200 |
commit | 2be9e6cc2677df7fe842c1a5980d6e0ffcf98fc9 (patch) | |
tree | b0d9af2d37e4d2cf71a87489975282ad4177e0b5 | |
parent | d2759e0e32c613b18123970ac15aa1f71949a5e7 (diff) | |
download | qtbase-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.h | 4 |
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; \ |