[Development] std::optional for Q_PROPERTY

Giuseppe D'Angelo giuseppe.dangelo at kdab.com
Fri Jul 21 11:35:56 CEST 2023


On 21/07/2023 11:01, Volker Hilsheimer via Development wrote:
> How about conversion:

I, for one, would like to stop seeing magic conversions added into 
QVariant, and keep breaking stuff at every Qt major release because we 
realize we went overboard and have to remove features.


Now, one could think of folding QVariant and std::optional nullability 
semantics, but this becomes hairy very very quick. Take this:


   std::optional<int> opt; // nullopt
   QVariant v = QVariant::fromValue(opt);

Is `v` a null QVariant with Int metatype, or a valid variant with a 
std::optional<int> metatype loaded with a copy of the optional? What if 
`opt` is loaded instead?

Bonus question: this works *today*, and guess what it does?


So this at a minimum is a different named constructor: 
QVariant::fromStdOptional or similar. This doesn't help at all in 
generic code (e.g. in the property system) -- when is one supposed to 
unwrap an optional vs keep it wrapped?


>      QVariant(std::optional<T>>).value<U>(); // return U{} if T cannot be converted; otherwise U(T);

This isn't how QVariant works today for 
`QVariant::fromValue(T{}).value<U>()`, unless T and U are a specific 
combination of types in a whitelist of sorts, or have a custom 
conversion registered; so, if anything, it should follow the same 
semantics: refuse the conversion, unless it's special or registered. And 
by "registered" I mean registered from `std::optional<T>` to `U`, not 
from `T` to `U`.



>      QVariant().value<std::optional<T>>(); // nullopt, not a std::optional holding a T{}
>      QVariant(42).value<std::optional<int>>(); // std::optional holding 42
>      QVariant(QSize()).value<std::optional<int>>(); // probably nullopt?

All of these already have established semantics. We can't change them 
without breaking API. We need an `optionalValue<T>()` accessor or 
something like that (again, that kills the idea of using this in generic 
code, properties, etc.).

> QVariant().value<std::optional<T>>();

Returns default-constructed std::optional<T> (i.e. nullopt)

> QVariant(42).value<std::optional<int>>(); // std::optional holding 42

No, returns nullopt, types don't match and not in the list of magical 
conversions (and we can't extend such a list because it's an API break)

> QVariant(QSize()).value<std::optional<int>>();

Nullopt again (types don't match).


My 2 c,
-- 
Giuseppe D'Angelo | giuseppe.dangelo at kdab.com | Senior Software Engineer
KDAB (France) S.A.S., a KDAB Group company
Tel. France +33 (0)4 90 84 08 53, http://www.kdab.com
KDAB - The Qt, C++ and OpenGL Experts

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4244 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.qt-project.org/pipermail/development/attachments/20230721/0e6d6734/attachment.bin>


More information about the Development mailing list