Можно ли получить возвращаемое значение из слота динамической реплики QRemoteObject?

Я не могу вызвать слот, возвращающий значение в QRemoteObjectDynamicReplica.

Похоже, что InvokeMethod на реплике не поддерживает возвращаемое значение. Мне удалось только вызвать void, возвращающие слоты, и даже в этом случае в режиме DirectConnection invokeMethod завершился до вызова слота хоста, поэтому кажется, что ответ хоста не находится в ожидании.

У меня есть такой код, который отлично работает на стороне хоста, но не на стороне реплики.

  bool success = QMetaObject::invokeMethod(_replica,"getName", Qt::DirectConnection,
      Q_RETURN_ARG(QString, retVal),
      Q_ARG(QString, "id")
   );

Если я хорошо понимаю тему REPC (я еще не пробовал), кажется, что вызов слотов с возвращаемым значением возможен: использование заключается в объявлении SLOT, за которым следует желаемая подпись, заключенная в скобки. Возвращаемое значение может быть включено в объявление. Если возвращаемое значение пропущено, void будет использоваться в сгенерированных файлах.

У REPC есть какая-то магия, чтобы разрешить эту функцию, или я что-то пропустил?

Спасибо за помощь.

2 ответа

Для тех, кто ищет ответ на этот вопрос, есть способ:):

QRemoteObjectPendingCall

недокументированный аргумент.

bool success = QMetaObject::invokeMethod(_replica,"getName",Qt::DirectConnection,
    Q_RETURN_ARG(QRemoteObjectPendingCall, call),
    Q_ARG(QString, "id")
 );
auto e = call.error();// , QRemoteObjectPendingCall::InvalidMessage);

call.waitForFinished();

//QVERIFY(call.isFinished());

qDebug() << QMetaType::typeName(call.returnValue().type());

QString retVal = call.returnValue().toString();

Это точно такой же вид будущего объекта, доступный для REPC Replica (кроме не шаблонного). Документация отсутствует, но есть пример в: Интеграционные тесты Qt Remote Objects.

К сожалению, в настоящее время (5.13.0) нет возможности получить ожидающий ответ в QML (QTBUG-77178), но люди Qt ищут его.

Принятый ответ вызывает метод с неправильной сигнатурой из-заQRemoteObjectPendingCall. Должен бытьQRemoteObjectPendingReply<T>. Вы получите что-то вроде этого:

QMetaMethod::invokeMethod: return type mismatch for method FooReplica::getName(QString): cannot convert from QRemoteObjectPendingReply<QString> to QRemoteObjectPendingCall during invocation

На самом деле это можно доказать, распечатав возвращаемое значение вызова.

qDebug() << success;-> ложь

Это выведет false, а не true, поскольку вы пытаетесь вызвать метод с неправильной сигнатурой, как указано внутренними компонентами Qt.

Это заставляет автора думать, что это удалось, потому что он вернулся быстро без тайм-аута по умолчанию в 30 секунд.

Но оно вернулось лишь быстро, потому что ждать было нечего. Если распечатать возвращаемое значениеwaitForFinishedпозвоните, и вы увидите, что это на самом деле ложно, поэтому это скорее правда.

qDebug() << call.waitForFinished();-> ложь

Затем будет сгенерирован QVariant(Invalid), который для QString будет просто «пустой строкой» (значение по умолчанию), а не тем, что должно было быть возвращено.

Мне потребовалось немало времени, чтобы разобраться, но я считаю, что в моих экспериментах мы все сталкиваемся с этой ошибкой как в Qt 5, так и в Qt 6 на Windows, Linux и Mac, как с qmake, так и с cmake.

https://lists.qt-project.org/pipermail/development/2023-October/044608.html

и

https://bugreports.qt.io/browse/QTBUG-94542

На момент написания этой статьи в настоящее время не существует исправления, но есть асинхронный обходной путь без ожидания:

      QRemoteObjectPendingCallWatcher* watcher =
  new QRemoteObjectPendingCallWatcher(_replica->getName("id"));
connect(watcher, &QRemoteObjectPendingCallWatcher::finished,
  [](QRemoteObjectPendingCallWatcher* watch)
{ 
  qDebug << watcher->returnValue().toString();
});
Другие вопросы по тегам