Можно ли получить возвращаемое значение из слота динамической реплики 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();
});