在QML中使用C++ - slot,返回命名空间中的类型

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(顺便说一句:我对库和使用它的应用程序使用相同的设置):

到目前为止,我的结论是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其中包含方法的返回类型:

另一方面,如果启用,则使用命名空间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)完成的

我认为"我们"可以将此称为错误(或疏忽)