我首先要提一下,在 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 相同的可选命名空间功能。