[Development] QFlags Zero handling

Olivier Goffart olivier at woboq.com
Sat Jan 21 17:10:04 CET 2017


On Samstag, 21. Januar 2017 11:30:40 CET Stephen Kelly wrote:
> Hi,
> 
> Does anyone know why QFlags has a constructor taking a Zero pointer? My
> guess is that it's a hack to make initializing like
> 
>  Qt::WindowFlags = 0
> 
> work?

Correct.
We want to be able to initialize it with the literal 0, but not with any int 
or unrelated enum value:

 Qt::WindowFlags foo = 0;  // should work
 Qt::WindowFlags bar = 42;  // should NOT work
 Qt::WindowFlags bar = Qt::DownArrow;  // MUST NOT work (unrelated enum)

So the trick is to allow the initialization with a pointer so we can use 0, 
but not anything that gets converted to an int. 

A QFlags(int) constructor would work with any enum or anything that can be 
converted to int. That would defeat the purpose of QFlags.

> The problem encountered is that porting tools convert that to
> 
>  Qt::WindowFlags = nullptr
> 
> which is undesirable.

Yes, this is a case in which 0 was desired over nullptr. The problem is that 
you now even get a warning if you use "= 0" with some warning options.
So the trick is not really working anymore.

I'm not aware of another trick to enable the implicit conversion from '0' and 
no other thing.

If we allow implicit conversion from int, but still want to disable conversion 
from other enums, we could come up to something like this:

 QFlags(T); // normal constructor for the enum type
 QFlags(int);  // allow conversion from int
 
 // disallow construction from all other enumerations
 template<typename X> 
 QFlags(X, std::enable_if_t<std::is_enum_v<X>> *= nullptr) = delete;

But I'd rather QFlags not being implicitly constructed from int.

> https://mail.kde.org/pipermail/kde-frameworks-devel/2017-January/042091.html
> 
> Is there a better solution to that with modern c++?

As mentioned in the link, if you don't want to use nullptr because it's not 
pretty, and you don't want to use 0 because of the warning. Then the remaining 
option is to force the default constructor:

  Qt::WindowFlags = {};

> PS:
> 
> I mentioned there that Q_NO_TYPESAFE_FLAGS is broken. [...]
> The define could be removed from qflags.h. Perhaps something could be
> changed in qnamespace.h to allow the code to compile instead (and make the
> enum meta objects not available), but it doesn't seem worth it.

Yes, Q_NO_TYPESAFE_FLAGS is broken, as are most of the Q_NO_XXX.
I guess it could be removed, since QFlags does not have runtime cost, there is 
no point of keeping it, even for qt lite.

-- 
Olivier

Woboq - Qt services and support - https://woboq.com - https://code.woboq.org



More information about the Development mailing list