lee*_*mes 16 c++ qt moc qml qt5
我首先要提到的是,以下工作正常到Qt 5.0.0 beta 1(也许是beta 2和RC也不知道),但在Qt 5.0.0最终版本中失败了.我只想参考Qt 5.0.0最终版本中看到的结果.所以很可能这与Qt5最近的变化有关.
在C++方面,我在命名空间中有一组类(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
Run Code Online (Sandbox Code Playgroud)
这些宏OAE_BEGIN/END_NAMESPACE
扩展为namespace OAE_NAMESPACE {
...... }
或者没有,就像Qt所做的那样<qglobal.h>
,只是在宏名称中用"OAE"替换"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 */
Run Code Online (Sandbox Code Playgroud)
在下面,当说"启用命名空间"时,我的意思是我声明了宏OAE_NAMESPACE
,在这种情况下是值oae
.
其中,我在QML中为我的应用程序的用户界面访问此类的实例和Player
类返回的类player()
.为此,我按如下方式注册类:
qmlRegisterType<Game>();
qmlRegisterType<Player>();
Run Code Online (Sandbox Code Playgroud)
我公司提供的QML前端的指针的一个实例Game
,称为theGame
内QML:
view.engine()->rootContext()->setContextProperty("theGame",
QVariant::fromValue<Game*>(game));
Run Code Online (Sandbox Code Playgroud)
在QML中,我像往常一样使用它.一个小例子应该打印一个指针地址player()
:
Rectangle {
width: 100; height: 100
Component.onCompleted: console.log(theGame.player())
}
Run Code Online (Sandbox Code Playgroud)
我得到以下结果,取决于我是否设置OAE_NAMESPACE
(顺便说一句:我对库和使用它的应用程序使用相同的设置):
当禁用命名空间,一切都按预期和QML打印我的指针:
Player(0x10b4ae0)
Run Code Online (Sandbox Code Playgroud)当启用命名空间(并using
使用库在C++代码中,所以我根本不更改代码)时,QML无法理解返回类型Game::player()
:
Error: Unknown method return type: Player*
Run Code Online (Sandbox Code Playgroud)当改变返回类型的Game::player()
到
oae::Player*
,一切都再正常工作:
oae::Player(0x10b4ae0)
Run Code Online (Sandbox Code Playgroud)到目前为止,我的结论是moc
不考虑我在课堂上放置的命名空间.我的第一个猜测是:嘿,moc
我不知道我在调用时定义了命名空间g++
,这就是我在.pro文件中所做的:
DEFINES += OAE_NAMESPACE=oae
Run Code Online (Sandbox Code Playgroud)
但是,当将返回类型更改OAE_NAMESPACE::Player*
为时,它仍然有效,因此moc 确实知道OAE_NAMESPACE
宏,但它既不会扩展OAE_BEGIN/END_NAMESPACE
宏,也不会完全解析命名空间.
moc
生成以下"stringdata",Player * Game::player() const
其中包含方法的返回类型:
当禁用命名空间和使用的返回类型Player*
:
"player\0Player*\0"
Run Code Online (Sandbox Code Playgroud)当启用命名空间和使用的返回类型Player*
:
"player\0Player*\0"
Run Code Online (Sandbox Code Playgroud)当启用命名空间和使用的返回类型OAE_NAMESPACE::Player*
:
"player\0oae::Player*\0"
Run Code Online (Sandbox Code Playgroud)另一方面,如果启用,则使用命名空间moc
返回的类名称QMetaObject::className()
.
我现在的结论是,我可以通过编写OAE_NAMESPACE::ClassName
而不是ClassName
在QObject元方法的签名中使用这些类型来解决这个问题.(嗯,有更好的宏OAE_PREPEND_NAMESPACE
).因为这在代码中看起来很糟糕,对我来说它甚至看起来都是错误的,因为该方法已经在命名空间中,是否有更好的解决方案?
现在也有OAE_BEGIN/END_MOC_NAMESPACE
(类似QT_BEGIN/END_MOC_NAMESPACE
),所以也许我需要那些?我不知道它们在Qt中的使用位置和方式,所以我应该在我的库中相应地使用它们,因为我想使用与Qt相同的可选命名空间功能.
小智 8
它真的在5.0.0a中有效吗?
我浏览了Qt 5.0.0源代码并查看了解析方法的位置,特别是返回类型(fyi,5.0.0\qtbase\src\tools\moc\moc.cpp:L160)并且没有命名空间检查(两者都没有)参数,所以player(Player* p)
也不会工作).然而,它是为类def(5.0.0\qtbase\src\tools\moc\moc.cpp:L620和L635)完成的
我认为"我们"可以将此称为错误(或疏忽)