16

我首先要提一下,在 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 前端提供了一个指向 a 实例的指针,在 QMLGame中调用theGame

view.engine()->rootContext()->setContextProperty("theGame",
        QVariant::fromValue<Game*>(game));

在 QML 中,我照常使用它。一个小例子应该打印一个指针地址player()

Rectangle {
    width: 100; height: 100
    Component.onCompleted: console.log(theGame.player())
}

我得到以下结果,具体取决于我是否设置了 a OAE_NAMESPACE(顺便说一句:我对库和使用它的应用程序使用相同的设置):

  • 禁用 namespace时,一切都按预期工作,QML 向我打印指针:

    Player(0x10b4ae0)
    
  • 启用命名空间时(以及using它在使用库的 C++ 代码中,所以我根本不更改代码),QML 无法理解的返回类型Game::player()

    Error: Unknown method return type: Player*
    
  • 返回类型更改Game::player()to 时 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其中包含方法的返回类型:

  • 禁用命名空间并使用返回类型时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)。由于这在代码中看起来很糟糕,而且对我来说它甚至似乎是错误的,因为该方法已经在 namespace中,有没有更好的解决方案?

现在也有OAE_BEGIN/END_MOC_NAMESPACE(类似于QT_BEGIN/END_MOC_NAMESPACE),所以也许我在任何地方都需要那些?我不知道它们在 Qt 中的何处/如何使用,因此我应该在我的库中相应地使用它们,因为我想使用与 Qt 相同的可选命名空间功能。

4

1 回答 1

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) 完成的

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

于 2013-01-11T12:58:04.723 回答