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

标签 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 派生的)(可以选择用编译器标志触发;这些类在一个单独的库中,并且该库将命名空间的使用作为一个选项留给用户图书馆)。一个类(class),在这里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 .

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

我为 QML 前端提供了一个指向 Game 实例的指针。 ,称为 theGame在 QML 中:
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宏,但它也不会扩展 OAE_BEGIN/END_NAMESPACE宏或者它根本不再解析命名空间。
    mocPlayer * 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 )。因为这在代码中看起来很糟糕,对我来说它甚至看起来是错误的,因为该方法已经在命名空间中,有更好的解决方案吗?

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

    最佳答案

    它真的适用于 5.0.0a 吗?

    我浏览了 Qt 5.0.0 源代码并查看了解析方法的位置,尤其是返回类型(仅供引用,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) 完成的

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

    关于c++ - 在 QML 中使用 C++-slot 返回命名空间中的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14086289/

    相关文章:

    qt - `Screen.pixelDensity` 在非可视组件中等于 0

    c++ - 在析构函数中进行函数调用是一种好习惯吗?

    c++ - 重载 + 运算符必须采用无参数或单参数链表

    c++ - Qt 5.6 中的 QtCharts

    python - 建议使用 Pyside/Qt 进行错误处理(try/catch 或异常)

    qt - QML SwipeView 具有不透明的背景。我怎样才能使它透明?

    c++ - 将 unicode 参数传递给 QApplication

    qt - QML中如何通过Drag and DropArea机制拖动一个Item的副本?

    qt - QML - 垂直滑动 View ?

    c++ - C++与QML之间的通信