Can't safely store enums in QVariant because QVariant::canConvert() returns true for all enum types
-
If I create a QVariant like this:
@Q_DECLARE_METATYPE(Qt::CheckState);
QVariant var = QVariant::fromValue(Qt::Checked);
@and then on the receiving side I want to make sure I have the right thing:
@if (contents.canConvertQt::CheckState())
qDebug() << "CheckState is " << contents.valueQt::CheckState();@that's all fine, but canConvert() will return true for any enum type:
@if (contents.canConvertQt::DropAction())
qDebug() << "DropAction is " << contents.valueQt::DropAction();@This works:
@if (!strcmp(contents.typeName(), "Qt::CheckState"))
qDebug() << "CheckState is " << contents.valueQt::CheckState();@but that seems clunky.
Is there a better way for me to check my QVariant and see what type of enum is stored in it?
-
From the "documentation":http://qt-project.org/doc/qt-5/qvariant.html#canConvert, canConvert() checks if it's generally possible to to convert your stored type to your specified type. It doesn't check if the stored type EQUALS your specified type:
[quote]canConvert() only reports the general ability of QVariant to convert between types given suitable data; it is still possible to supply data which cannot actually be converted.
For example, canConvert(Int) would return true when called on a variant containing a string because, in principle, QVariant is able to convert strings of numbers to integers.[/quote]
Like you've discovered, to guarantee 100% correctness, you need to use QVariant::typeName() or QVariant::type() (the latter is useful if you are storing "predefined Qt types":http://qt-project.org/doc/qt-5/qmetatype.html#Type-enum only)
You can make your code more expressive like this:
@
// Short-code version:
if (contents.typeName() == QString("Qt::CheckState"))// CPU-efficient version:
if (contents.typeName() == QStringLiteral("Qt::CheckState"))
@ -
Hi,
@
if(contents.userType() == qMetaTypeIdQt::CheckState())
@@
But, seems thatif (contents.typeName() == QLatin1String("Qt::CheckState"))
is better that
if (contents.typeName() == QStringLiteral("Qt::CheckState"))
see http://comments.gmane.org/gmane.comp.lib.qt.qt5-feedback/1368
@ -
[quote author="1+1=2" date="1391846748"]
@if(contents.userType() == qMetaTypeIdQt::CheckState())@
[/quote]Ah, good one! I missed that. This is the most efficient solution.[quote author="1+1=2" date="1391846748"]
@if (contents.typeName() == QLatin1String("Qt::CheckState"))@
is better that
@if (contents.typeName() == QStringLiteral("Qt::CheckState"))@
[/quote]Are you sure? I think we can't tell without profiling because you'd still need to construct a new, temporary QLatin1String every time you make a comparison, and then destroy the temporary string after each comparison. QStringLiterals don't need construction or destruction -- that's why they were invented in the first place.(Most of the time though, the differences between QString, QStringLiteral and QLatin1String are negligible. I sometimes use the clearest code instead of the fastest code.)