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?


  • Moderators

    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 that

    if (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
    @


  • Moderators

    [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.)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.