Conversion from QFlags<> to QVariant could be easier
-
Consider the following code snippet from a run-of-the-mill implementation of the
data()function by a class which inheritsQAbstractItemModel:QVariant MyModel::data(const QModelIndex &index, int role) const { QVariant retval; // this doesn't compile ... I am told by the compiler: // "error: ‘template<class T> class QFlags’ used without template parameters" // QFlags::Int i = 0; // ...but this does: uint i = 0; if (index.isValid()) { int row = index.row(); int col = index.column(); switch (role) { case Qt::TextAlignmentRole: switch(col) { case 0: // this doesn't compile: // "error: no match for ‘operator=’ // (operand types are ‘QVariant’ and ‘QFlags<Qt::AlignmentFlag>’)": // retval = Qt::AlignLeft | Qt::AlignVCenter; // but this compiles: i = Qt::AlignLeft | Qt::AlignVCenter; retval = i; break; default: i = Qt::AlignHCenter | Qt::AlignVCenter; retval = i; break; } break; case Qt::DisplayRole: // etc.Since this idiom is used in so many places, I wouldn't think that it would be necessary to store a
QFlags<>value instantiated with any native Qt types in a temporary variable just so that I can write it to aQVariant; there should be aQFlags::operator QVariant()or something.Now I noticed that there is a
typedef QFlags::Intwhich is supposed to resolve either to signed or unsignedintdepending on how it is implemented. But I haven't figured out how to use it, so I take my chances withunsigned intand hope that I never have to compare it with a signed value anywhere.Is there a better way to do this?
(EDIT: OK, I need to define
ilike this, then it will be the correct type:QFlags<Qt::AlignmentFlag>::Int i = 0;but I am still stuck with an intermediate variable I really shouldn't need...
-
What about
QVariant::fromValue(Qt::AlignHCenter | Qt::AlignVCenter)? -
@sierdzio : It compiles, but it doesn't seem to work correctly ... everything is left-aligned and vertically top-aligned when I set the return value like this. When I cast it to an integer before setting the
QVariantreturn value, it works correctly. I really don't know what is happening; however, I suspect that theQt::AlignmentFlagjust doesn't have any metadata associated with it which might tellQVarianthow to convert it (either directly or by usingQVariant::fromValue()). The reverse conversion using the templatedQVariant::value<>()function also fails to convert it correctly. -
If nothing helps why not just write your own toVariant(QFlags<>) - function?
-
Don't assume ints or uints. There's a typedef for that and conversion operators.
It's a bit of a mouthful but the "correct" way to convert flags to and from variant is:Qt::Alignment original = Qt::AlignLeft | Qt::AlignVCenter; QVariant v = static_cast<Qt::Alignment::Int>(original); Qt::Alignment retrieved = static_cast<Qt::Alignment>(v.value<Qt::Alignment::Int>());so in your case it would look like this in the
data()method:retval = static_cast<Qt::Alignment::Int>(Qt::AlignLeft | Qt::AlignVCenter);and then on the receiving end:
Qt::Alignment a = static_cast<Qt::Alignment>(index.data(role).value<Qt::Alignment::Int>()); -
Don't assume ints or uints. There's a typedef for that and conversion operators.
It's a bit of a mouthful but the "correct" way to convert flags to and from variant is:Qt::Alignment original = Qt::AlignLeft | Qt::AlignVCenter; QVariant v = static_cast<Qt::Alignment::Int>(original); Qt::Alignment retrieved = static_cast<Qt::Alignment>(v.value<Qt::Alignment::Int>());so in your case it would look like this in the
data()method:retval = static_cast<Qt::Alignment::Int>(Qt::AlignLeft | Qt::AlignVCenter);and then on the receiving end:
Qt::Alignment a = static_cast<Qt::Alignment>(index.data(role).value<Qt::Alignment::Int>());@chris-kawa : Thank you for the detailed explanation. It is a little less typing to write
Qt::Alignment::Intinstead of
QFlags<Qt::AlignmentFlag>::IntMaybe I will take Christian Ehrlicher's advice and write the
toVariant()function? It sounds like a good idea. I was just wondering why this isn't already built into theQVariantclass? -
@chris-kawa : Thank you for the detailed explanation. It is a little less typing to write
Qt::Alignment::Intinstead of
QFlags<Qt::AlignmentFlag>::IntMaybe I will take Christian Ehrlicher's advice and write the
toVariant()function? It sounds like a good idea. I was just wondering why this isn't already built into theQVariantclass?@robert-hairgrove said in Conversion from QFlags<> to QVariant could be easier:
I was just wondering why this isn't already built into the QVariant class?
QFlagsis a template so QVariant would have to support all possible specializations, for all possible enum types, which is unrealistic.
It could be supported on theQFlagsside with something liketoVariant()andfromVariant(), but if you take a step back this doesn't scale well, because then why nottoString,toDouble,toWhatever?The best place for this IMO would be outside both
QVariantandQFlags, with a function template that would basically do the casts I mentioned. My guess is it's not in Qt because nobody felt like this was big enough of a deal and it wouldn't even be that much shorter either.Anyway, those are basically one-liners, so you can easily provide them yourself if you feel like it.
-
@robert-hairgrove said in Conversion from QFlags<> to QVariant could be easier:
I was just wondering why this isn't already built into the QVariant class?
QFlagsis a template so QVariant would have to support all possible specializations, for all possible enum types, which is unrealistic.
It could be supported on theQFlagsside with something liketoVariant()andfromVariant(), but if you take a step back this doesn't scale well, because then why nottoString,toDouble,toWhatever?The best place for this IMO would be outside both
QVariantandQFlags, with a function template that would basically do the casts I mentioned. My guess is it's not in Qt because nobody felt like this was big enough of a deal and it wouldn't even be that much shorter either.Anyway, those are basically one-liners, so you can easily provide them yourself if you feel like it.
@chris-kawa Thank you.