Прежде всего хочу сказать, что следующее работало отлично до Qt 5.0.0 beta 1 (возможно, бета 2 и RC тоже, не знаю), но не работает в Qt 5.0.0 финальная версия. Я хочу только обратиться к результатам, представленным в окончательной версии Qt 5.0.0. Скорее всего, это связано с недавними изменениями в Qt5.Используйте C++ - слот в QML, который возвращает тип в пространстве имен
На стороне С ++ У меня есть набор классов (QObject-производный) в пространстве имен (который, возможно, запускается с флагами компилятора, классы находятся в отдельной библиотеке, и библиотека оставляет использование пространства имен в качестве опции для пользователь библиотеки). Класс, вот Game
, может выглядеть следующим образом (выдержка):
OAE_BEGIN_NAMESPACE
// forward-declarations:
class Player; // Player is just another class in the same library
class Game : public QObject
{
Q_OBJECT
public:
explicit Game(...);
public slots:
Player *player() const; // <-- the quesion is about such slots
};
OAE_END_NAMESPACE
макросы OAE_BEGIN/END_NAMESPACE
расширить либо namespace OAE_NAMESPACE {
... }
или ничего, так же, как Qt делает это в <qglobal.h>
, просто «QT» заменить с «ОПЭ» в именах макросов:
#ifndef OAE_NAMESPACE
# define OAE_PREPEND_NAMESPACE(name) ::name
# define OAE_USE_NAMESPACE
# define OAE_BEGIN_NAMESPACE
# define OAE_END_NAMESPACE
# define OAE_BEGIN_INCLUDE_NAMESPACE
# define OAE_END_INCLUDE_NAMESPACE
# define OAE_BEGIN_MOC_NAMESPACE
# define OAE_END_MOC_NAMESPACE
# define OAE_FORWARD_DECLARE_CLASS(name) class name;
# define OAE_FORWARD_DECLARE_STRUCT(name) struct name;
# define OAE_MANGLE_NAMESPACE(name) name
#else /* user namespace */
# define OAE_PREPEND_NAMESPACE(name) ::OAE_NAMESPACE::name
# define OAE_USE_NAMESPACE using namespace ::OAE_NAMESPACE;
# define OAE_BEGIN_NAMESPACE namespace OAE_NAMESPACE {
# define OAE_END_NAMESPACE }
# define OAE_BEGIN_INCLUDE_NAMESPACE }
# define OAE_END_INCLUDE_NAMESPACE namespace OAE_NAMESPACE {
# define OAE_BEGIN_MOC_NAMESPACE OAE_USE_NAMESPACE
# define OAE_END_MOC_NAMESPACE
# define OAE_FORWARD_DECLARE_CLASS(name) \
OAE_BEGIN_NAMESPACE class name; OAE_END_NAMESPACE \
using OAE_PREPEND_NAMESPACE(name);
# define OAE_FORWARD_DECLARE_STRUCT(name) \
OAE_BEGIN_NAMESPACE struct name; OAE_END_NAMESPACE \
using OAE_PREPEND_NAMESPACE(name);
# define OAE_MANGLE_NAMESPACE0(x) x
# define OAE_MANGLE_NAMESPACE1(a, b) a##_##b
# define OAE_MANGLE_NAMESPACE2(a, b) OAE_MANGLE_NAMESPACE1(a,b)
# define OAE_MANGLE_NAMESPACE(name) OAE_MANGLE_NAMESPACE2(\
OAE_MANGLE_NAMESPACE0(name), OAE_MANGLE_NAMESPACE0(OAE_NAMESPACE))
namespace OAE_NAMESPACE {}
# ifndef OAE_BOOTSTRAPPED
# ifndef OAE_NO_USING_NAMESPACE
/*
This expands to a "using OAE_NAMESPACE" also in _header files_.
It is the only way the feature can be used without too much
pain, but if people _really_ do not want it they can add
DEFINES += OAE_NO_USING_NAMESPACE to their .pro files.
*/
OAE_USE_NAMESPACE
# endif
# endif
#endif /* user namespace */
в дальнейшем, когда говорят «позволяет пространство имен», я имею в виду, я объявил макрос OAE_NAMESPACE
, в этом случае со значением oae
.
Среди прочих, я обращаюсь к экземплярам этого класса и классу Player
, возвращенным player()
из QML для пользовательского интерфейса моего приложения. Для этого я зарегистрировать классы следующим образом:
qmlRegisterType<Game>();
qmlRegisterType<Player>();
Я обеспечить QML FRONTEND указатель на экземпляр Game
, называемый theGame
внутри QML:
view.engine()->rootContext()->setContextProperty("theGame",
QVariant::fromValue<Game*>(game));
В пределах QML, я использую это как обычный.Небольшой пример должен напечатать указатель адрес player()
:
Rectangle {
width: 100; height: 100
Component.onCompleted: console.log(theGame.player())
}
Я получаю следующие результаты, в зависимости от того установлен ли я OAE_NAMESPACE
или нет (кстати: я использую те же настройки, как для библиотеки а приложение, использующее его):
При отключив имен, все работает, как ожидалось, и QML печатает мне указатель:
Player(0x10b4ae0)
Когда позволяет пространство имен (и
using
его в коде C++ с использованием библиотеки, так что я не изменить код на всех), QML не в состоянии понять тип возвращаемогоGame::player()
:Error: Unknown method return type: Player*
При изменении типа возвращаемого из
Game::player()
вoae::Player*
, все отлично снова работает:oae::Player(0x10b4ae0)
Мой вывод до сих пор является то, что moc
не рассматривает пространство имен я ставлю вокруг класса. Моя первая догадка: Эй, moc
не знает, что я определить пространство имен при вызове g++
, что это то, что я делаю в файле .pro:
DEFINES += OAE_NAMESPACE=oae
Однако при изменении типа возвращаемого значения OAE_NAMESPACE::Player*
, его все еще работает, поэтому moc делает знанием макроса OAE_NAMESPACE
, но он не расширяет макросы OAE_BEGIN/END_NAMESPACE
или не разбирает пространства имен вообще.
moc
производит следующую "StringData" для Player * Game::player() const
, который containes метода в тип возвращаемого:
При отключение пространства имен и используя тип возвращаемого
Player*
:"player\0Player*\0"
Когда включение пространства имен и использование типа возврата
Player*
:"player\0Player*\0"
Когда позволяет пространство имен и использовать тип возвращаемого
OAE_NAMESPACE::Player*
:"player\0oae::Player*\0"
С другой стороны, moc
добавлять в начало названия класса, возвращаемый QMetaObject::className()
с пространством имен, если включен.
Мой вывод теперь, что я мог это исправить, написав OAE_NAMESPACE::ClassName
вместо ClassName
всякий раз, когда использование этих типов в подписи QObject мета методов. (Ну, есть лучший макрос OAE_PREPEND_NAMESPACE
). Так как это выглядело бы ужасно в коде, и для меня это даже кажется неправильным, потому что метод уже находится в пространстве имен, есть ли лучшее решение?
Теперь также OAE_BEGIN/END_MOC_NAMESPACE
(аналог QT_BEGIN/END_MOC_NAMESPACE
), поэтому, возможно, мне нужны те, где-нибудь? Я не знаю, где/как они используются в Qt, поэтому я должен использовать их соответственно в своей библиотеке, так как я хочу использовать ту же опционную функцию пространства имен, что и Qt.
Я добавлю некоторую информацию о том, какой код создавался moc (например, была проанализирована подпись слота). – leemes
Использует ли qmlRegisterType <> имя класса с именами? – mlvljr
@mlvjr Спасибо за подсказку, но я уже пробовал это. На самом деле это ничего не меняет, поскольку это спецификатор типа C++, но это о том, как 'moc' анализирует файл заголовка. Он не обнаруживает, что 'Player' в пространстве имен фактически ссылается на класс' oae :: Player' при использовании вне пространства имен. Также я считаю, что это поведение было другим в Qt 5.0.0 alpha и beta1. – leemes