I first want to mention that the following worked fine up to Qt 5.0.0 beta 1 (maybe beta 2 and RC too, don't know), but fails in Qt 5.0.0 final release version. I only want to refer to the results seen in Qt 5.0.0 final release version. So most probably this has something to do with recent changes in Qt5.
On C++ side I have a set of classes (QObject-derived) in a namespace (which is optionally triggered with compiler flags; the classes are in a separate library and the library leaves the usage of a namespace as an option to the user of the library). A class, here Game
, might look like this (excerpt):
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
The macros OAE_BEGIN/END_NAMESPACE
expand to either namespace OAE_NAMESPACE {
... }
or nothing, in the same way Qt does it in <qglobal.h>
, just "QT" replaced with "OAE" in the macro names:
#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 */
In the following, when saying "enabling the namespace", I mean I declared the macro OAE_NAMESPACE
, in this case with the value oae
.
Among others, I access instances of this class and the Player
class as returned by player()
from within QML for the user interface of my application. For this, I register the classes as follows:
qmlRegisterType<Game>();
qmlRegisterType<Player>();
I provide the QML frontend a pointer to an instance of a Game
, called theGame
within QML:
view.engine()->rootContext()->setContextProperty("theGame",
QVariant::fromValue<Game*>(game));
Within QML, I use this as usual. A small example should print a pointer address of the player()
:
Rectangle {
width: 100; height: 100
Component.onCompleted: console.log(theGame.player())
}
I get the following results, depending on whether I set a OAE_NAMESPACE
or not (by the way: I use the same setting for both the library and the application using it):
When disabling the namespace, everything works as expected and QML prints me the pointer:
Player(0x10b4ae0)
When enabling the namespace (and using
it in the C++ code using
the library, so I don't change the code at all), QML fails to
understand the return type of Game::player()
:
Error: Unknown method return type: Player*
When changing the return type of Game::player()
to
oae::Player*
, everything works fine again:
oae::Player(0x10b4ae0)
My conclusion so far is that moc
doesn't consider the namespace I put around the class. My first guess was: Hey, moc
doesn't know that I define the namespace when calling g++
, which is what I do in the .pro file:
DEFINES += OAE_NAMESPACE=oae
However, when changing the return type to OAE_NAMESPACE::Player*
, it still works, so moc does know of the OAE_NAMESPACE
macro, but it doesn't either expand the OAE_BEGIN/END_NAMESPACE
macros or it doesn't parse namespaces at all anymore.
moc
produces the following "stringdata" for Player * Game::player() const
which containes the method's return type:
When disabling the namespace and using the return type Player*
:
"player\0Player*\0"
When enabling the namespace and using the return type Player*
:
"player\0Player*\0"
When enabling the namespace and using the return type OAE_NAMESPACE::Player*
:
"player\0oae::Player*\0"
On the other side, moc
prepends class names as returned by QMetaObject::className()
with the namespace if enabled.
My conclusion now is that I could fix this by writing OAE_NAMESPACE::ClassName
instead of ClassName
whenever using these types in the signatures of QObject meta methods. (Well, there is the better macro OAE_PREPEND_NAMESPACE
). Since this would look horrible in the code, and to me it even seems wrong because the method already is in the namespace, is there a better solution?
Now there also is OAE_BEGIN/END_MOC_NAMESPACE
(analogous to QT_BEGIN/END_MOC_NAMESPACE
), so maybe I need those anywhere? I don't know where/how they are used in Qt, so I should use them accordingly in my library, since I want to use the same optional namespace feature as Qt does.
Did it really worked in 5.0.0a?
I browsed through Qt 5.0.0 source code and looked where methods are parsed, especially the return type (fyi, 5.0.0\qtbase\src\tools\moc\moc.cpp:L160) and there are no namespace check (neither on the arguments, so player(Player* p)
won't work either).
Whereas, it's done for the class def (5.0.0\qtbase\src\tools\moc\moc.cpp:L620 & L635)
I think "we" can call this a bug (or an oversight)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With