Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QMetaType::convert failed
Forum Updated to NodeBB v4.3 + New Features

QMetaType::convert failed

Scheduled Pinned Locked Moved Unsolved General and Desktop
6 Posts 2 Posters 2.8k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • W Offline
    W Offline
    wxfred
    wrote on last edited by
    #1

    Source code:

    ...
    ids[j] = QMetaType::type(parameterTypes[j]); // parameterTypes[j] is a enum of QMetaType
    if (ids[j] != QMetaType::UnknownType)
    {
        types[j] = QMetaType::create(ids[j]);
        QJsonValue value = model.value(parameterNames[j]); // model is a QJsonObject
        if (!QMetaType::convert(&value, QMetaType::QVariant, types[j], ids[j]))
        {
            qDebug() << "convert to type: " << ids[j] << " failed";
        }
        ...
    }
    

    After the failed of QMetaType::convert, I tested the functions below:

    qDebug() << QMetaType::hasRegisteredConverterFunction(QMetaType::QJsonValue, QMetaType::QString);
    qDebug() << QMetaType::hasRegisteredConverterFunction(QMetaType::QVariant, QMetaType::QVariant);
    qDebug() << QMetaType::hasRegisteredConverterFunction(QMetaType::Int, QMetaType::Int);
    

    All results were false.

    So, why did these happened? I tested them in Qt 5.9 and Qt 5.7.

    kshegunovK 1 Reply Last reply
    0
    • W Offline
      W Offline
      wxfred
      wrote on last edited by
      #2

      Sorry, I made a mistake. The 7th line in the first code block should be

      if (!QMetaType::convert(&value, QMetaType::QJsonValue, types[j], ids[j]))
      
      1 Reply Last reply
      0
      • W wxfred

        Source code:

        ...
        ids[j] = QMetaType::type(parameterTypes[j]); // parameterTypes[j] is a enum of QMetaType
        if (ids[j] != QMetaType::UnknownType)
        {
            types[j] = QMetaType::create(ids[j]);
            QJsonValue value = model.value(parameterNames[j]); // model is a QJsonObject
            if (!QMetaType::convert(&value, QMetaType::QVariant, types[j], ids[j]))
            {
                qDebug() << "convert to type: " << ids[j] << " failed";
            }
            ...
        }
        

        After the failed of QMetaType::convert, I tested the functions below:

        qDebug() << QMetaType::hasRegisteredConverterFunction(QMetaType::QJsonValue, QMetaType::QString);
        qDebug() << QMetaType::hasRegisteredConverterFunction(QMetaType::QVariant, QMetaType::QVariant);
        qDebug() << QMetaType::hasRegisteredConverterFunction(QMetaType::Int, QMetaType::Int);
        

        All results were false.

        So, why did these happened? I tested them in Qt 5.9 and Qt 5.7.

        kshegunovK Offline
        kshegunovK Offline
        kshegunov
        Moderators
        wrote on last edited by
        #3

        @wxfred said in QMetaType::convert failed:

        So, why did these happened?

        Probably there aren't any conversions between those types. What are you trying to do? Give us some context here.

        Read and abide by the Qt Code of Conduct

        W 1 Reply Last reply
        0
        • kshegunovK kshegunov

          @wxfred said in QMetaType::convert failed:

          So, why did these happened?

          Probably there aren't any conversions between those types. What are you trying to do? Give us some context here.

          W Offline
          W Offline
          wxfred
          wrote on last edited by
          #4

          @kshegunov Ok. What I suppose to accomplish is something like model binding within actions of .net mvc. The basic procedure is:
          firstly, extracting parameters in url to a QJsonObject;
          secondly, using QMetaMethod::parameterTypes() and QMetaMethod::parameterNames() to get the info of parameters of my action function;
          thanks to Qt's reflection, finally, matching the parameters in QJsonObject to my action function's parameters.

          In the last step, for example, if I extract a QJsonObject from url like this:

          model = {
              username: "wxfred",
              password: "123456"
          }
          

          and my action function is something like this:

          Q_INVOKABLE QJsonObject login(const QString &username, const QString &password)
          {
              ...
          }
          

          then, I will use the code below to pair the parameters and invoke my action function:

          int count = metaMethod.parameterCount();  // get the total num of my action function's parameters
          QList<QByteArray> parameterTypes = metaMethod.parameterTypes(); // parameterTypes[0] will be "QString", parameterTypes[1] will also be "QString"
          QList<QByteArray> parameterNames = metaMethod.parameterNames(); // [0] is "username", [1] is "password"
          QVector<int> ids; // the meta type id of each parameter
          QVector<void*> instances; // the instance of each parameter
          for (int j = 0; j < count; ++j)
          {
              ids[j] = QMetaType::type(parameterTypes[j]); // get meta type id, for "QString" the id is QMetaType::QString
              instances[j] = QMetaType::create(ids[j]); // dynamically create instance by id
              QJsonValue value = model.value(parameterNames[j]); // get contents of parameters in model, in my example, the first parameter's name in action function is "username", and "username" is the key of "wxfred" in model, finally, the value will be a QJsonValue(QString("wxfred"))
              if (!QMetaType::convert(&value, QMetaType::QJsonValue, instances[j], ids[j])) // convert, this step is always failed
              {
                  qDebug() << "convert to type: " << ids[j] << " failed";
              }
          

          If QMetaType::convert is function well as I expect, I can invoke my action function with these instances of parameters by QMetaObject.invokeMethod. But it dose not.
          What is even more frustrating is that, although Qt supports QMetaType::registerConverter(MemberFunction function) to register converter function, you can't register the converter of two basic meta types. For example,

          int method(QJsonValue value)
          {
              ...
          }
          QMetaType::registerConverter<QJsonValue, int>(&method);
          

          build these code will get error:

          D:\Qt\Qt5.9.0\5.9\msvc2015_64\include\QtCore\qmetatype.h:636: error: C2338: QMetaType::registerConverter: At least one of the types must be a custom type.
          

          That's weird, because if Qt dose not implement the converter between basic meta types, why dose it fobidden user to implement them?

          kshegunovK 1 Reply Last reply
          0
          • W wxfred

            @kshegunov Ok. What I suppose to accomplish is something like model binding within actions of .net mvc. The basic procedure is:
            firstly, extracting parameters in url to a QJsonObject;
            secondly, using QMetaMethod::parameterTypes() and QMetaMethod::parameterNames() to get the info of parameters of my action function;
            thanks to Qt's reflection, finally, matching the parameters in QJsonObject to my action function's parameters.

            In the last step, for example, if I extract a QJsonObject from url like this:

            model = {
                username: "wxfred",
                password: "123456"
            }
            

            and my action function is something like this:

            Q_INVOKABLE QJsonObject login(const QString &username, const QString &password)
            {
                ...
            }
            

            then, I will use the code below to pair the parameters and invoke my action function:

            int count = metaMethod.parameterCount();  // get the total num of my action function's parameters
            QList<QByteArray> parameterTypes = metaMethod.parameterTypes(); // parameterTypes[0] will be "QString", parameterTypes[1] will also be "QString"
            QList<QByteArray> parameterNames = metaMethod.parameterNames(); // [0] is "username", [1] is "password"
            QVector<int> ids; // the meta type id of each parameter
            QVector<void*> instances; // the instance of each parameter
            for (int j = 0; j < count; ++j)
            {
                ids[j] = QMetaType::type(parameterTypes[j]); // get meta type id, for "QString" the id is QMetaType::QString
                instances[j] = QMetaType::create(ids[j]); // dynamically create instance by id
                QJsonValue value = model.value(parameterNames[j]); // get contents of parameters in model, in my example, the first parameter's name in action function is "username", and "username" is the key of "wxfred" in model, finally, the value will be a QJsonValue(QString("wxfred"))
                if (!QMetaType::convert(&value, QMetaType::QJsonValue, instances[j], ids[j])) // convert, this step is always failed
                {
                    qDebug() << "convert to type: " << ids[j] << " failed";
                }
            

            If QMetaType::convert is function well as I expect, I can invoke my action function with these instances of parameters by QMetaObject.invokeMethod. But it dose not.
            What is even more frustrating is that, although Qt supports QMetaType::registerConverter(MemberFunction function) to register converter function, you can't register the converter of two basic meta types. For example,

            int method(QJsonValue value)
            {
                ...
            }
            QMetaType::registerConverter<QJsonValue, int>(&method);
            

            build these code will get error:

            D:\Qt\Qt5.9.0\5.9\msvc2015_64\include\QtCore\qmetatype.h:636: error: C2338: QMetaType::registerConverter: At least one of the types must be a custom type.
            

            That's weird, because if Qt dose not implement the converter between basic meta types, why dose it fobidden user to implement them?

            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by
            #5

            I don't have an answer for you currently, sorry. I'll need to check Qt's sources, but I'm quite busy now, I hope someone will pitch in and add some suggestion. I assume that Qt does the conversion internally, so that's why there are no registered converters for its types.

            Read and abide by the Qt Code of Conduct

            W 1 Reply Last reply
            0
            • kshegunovK kshegunov

              I don't have an answer for you currently, sorry. I'll need to check Qt's sources, but I'm quite busy now, I hope someone will pitch in and add some suggestion. I assume that Qt does the conversion internally, so that's why there are no registered converters for its types.

              W Offline
              W Offline
              wxfred
              wrote on last edited by
              #6

              @kshegunov Thanks for your reminding. I checked the source code of the QMetaType, and found this:

              bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId)
              {
                  const QtPrivate::AbstractConverterFunction * const f =
                      customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId));
                  return f && f->convert(f, from, to);
              }
              
              bool QMetaType::registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to)
              {
                  if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from, to), f)) {
                      qWarning("Type conversion already registered from type %s to type %s",
                               QMetaType::typeName(from), QMetaType::typeName(to));
                      return false;
                  }
                  return true;
              }
              
              bool QMetaType::hasRegisteredConverterFunction(int fromTypeId, int toTypeId)
              {
                  return customTypesConversionRegistry()->contains(qMakePair(fromTypeId, toTypeId));
              }
              

              All these 3 methods use the same function named customTypesConversionRegistry. Literally, these methods only consider about the converters of user's custom types, but in Qt Assistant, their descriptions say nothing about "custom" things, how annoying!
              I still can't find an API to convert a object of QJsonValue or QVariant to a preallocated space whose type is determined by a enum of QMetaType::Type. But, in the source code, Qt uses "switch/case" to handle the stream operations of meta types, so I borrowed it and made some change. Now it works fine, maybe.

              Qt's load method:

              bool QMetaType::load(QDataStream &stream, int type, void *data)
              {
                  if (!data || !isRegistered(type))
                      return false;
              
                  switch(type) {
              ...
                  case QMetaType::Long: {
                      qlonglong l;
                      stream >> l;
                      *static_cast<long *>(data) = long(l);
                      break; }
                  case QMetaType::Int:
                      stream >> *static_cast<int *>(data);
                      break;
              ...
              }
              

              my converter:

              bool convert(const QVariant &variant, int type, void *data)
              {
                  if (!data || !QMetaType::isRegistered(type)) return false;
              
                  bool ok = false;
              
                  switch (type) {
              ...
                  case QMetaType::Long:
                      *static_cast<long *>(data) = (long)variant.toLongLong(&ok);
                      break;
                  case QMetaType::Int:
                      *static_cast<int *>(data) = variant.toInt(&ok);
                      break;
              ...
              }
              
              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved