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

时间:2012-12-29 21:58:06

标签: c++ qt qml qt5 moc

我首先要提到的是,以下工作正常至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

OAE_BEGIN/END_NAMESPACE扩展为namespace OAE_NAMESPACE { ... }或者没有任何内容,就像Qt在<qglobal.h>中所做的那样,只是将“QT”替换为“ OAE“在宏名称中:

#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

其中,我从QML中为我的应用程序的用户界面访问此类的实例和Player返回的player()类。为此,我按如下方式注册类:

qmlRegisterType<Game>();
qmlRegisterType<Player>();

我向QML前端提供指向Game实例的指针,在QML中称为theGame

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宏,但它不会展开{ {1}}宏或它根本不解析名称空间。

OAE_BEGIN/END_NAMESPACEmoc生成以下“stringdata”,其中包含方法的返回类型:

  • 禁用命名空间并使用返回类型Player * Game::player() const时:

    Player*
  • 启用命名空间并使用返回类型"player\0Player*\0" 时:

    Player*
  • 启用命名空间并使用返回类型"player\0Player*\0" 时:

    OAE_NAMESPACE::Player*

另一方面,"player\0oae::Player*\0" moc返回的类名添加到名称空间(如果已启用)。

我现在的结论是,只要在QObject元方法的签名中使用这些类型,我就可以通过编写QMetaObject::className()而不是OAE_NAMESPACE::ClassName来解决此问题。 (好吧,有更好的宏ClassName)。因为这在代码中看起来很糟糕,对我来说它甚至看起来都是错误的,因为方法已经在命名空间中是否有更好的解决方案?

现在还有OAE_PREPEND_NAMESPACE(类似于OAE_BEGIN/END_MOC_NAMESPACE), 所以我可能需要其他地方 ?我不知道它们在Qt中的使用位置和方式,所以我应该在我的库中相应地使用它们,因为我想使用与Qt相同的可选命名空间功能。

1 个答案:

答案 0 :(得分: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&amp; L635)完成的

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