【问题标题】:Q_ENUMS and using declarations do not work togetherQ_ENUMS 和 using 声明不能一起工作
【发布时间】:2017-03-23 13:25:06
【问题描述】:

考虑以下类定义:

// exported.hpp

#include <QObject>

class Exported: public QObject {
    Q_OBJECT

public:
    using QObject::QObject;
    enum class FOO { BAR };
    Q_ENUM(FOO)
};

还有以下main文件:

// main.cpp

#include <QApplication>
#include <QQmlApplicationEngine>
#include "exported.hpp"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;
    qmlRegisterType<Exported>("Package", 1, 0, "Exported");
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    return app.exec();
}

通过这样做,我可以轻松地在 QML 中访问我的枚举的命名常量。
举个例子:

// main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import Package 1.0

ApplicationWindow {
    Rectangle {
        Component.onCompleted: {
            console.log(Exported.BAR)
        }
    }
}

只要枚举的声明包含在类中,这就会起作用。
例如,如果我按如下所示更改类定义,它就不再起作用了:

// exported.hpp

#include <QObject>

enum class FOO { BAR };

class Exported: public QObject {
    Q_OBJECT

public:
    using QObject::QObject;
    using FOO = ::FOO;
    Q_ENUM(FOO)
};

现在,QML 文件中的Exported.BARundefined


最基本的问题是:为什么它不适用于 using 声明
请注意,它适用于转发声明,例如:

// exported.hpp

#include <QObject>

enum class FOO { BAR };

class Exported: public QObject {
    Q_OBJECT

public:
    using QObject::QObject;
    enum class FOO;
    Q_ENUM(FOO)
    enum class FOO { BAR };
};

Q_ENUMdocumentation 实际上是这样(强调我的):

这个宏向元对象系统注册一个枚举类型。 它必须放在具有 Q_OBJECT 或 Q_GADGET 宏的类中的枚举声明之后

在整个部分中没有提及定义。
另一方面,我们从标准中得到了这个:

using-declaration 将一组声明引入到 using-declaration 出现的声明区域中。

所以,我期待它也能正常工作。无论如何,这对我来说可能是一个错误的期望。

也就是说,有什么建议可以解决这样的不便吗?
如果 enum 是在类之外定义的,我可以看到解决它的唯一方法是在类中定义另一个 enum 并具有一对一它们之间的映射。
它远非可维护而且确实有点乏味。

【问题讨论】:

    标签: c++ qt c++11 qt5 using-declaration


    【解决方案1】:

    这与标准 C++ 无关,至少没有直接关系。 Qt 的moc 对 C++ 语法规则的理解非常有限(并且有充分的理由1)。显然,这种将枚举导入类范围的方式超出了它的能力范围。

    在我的代码中,当我希望 moc 为我生成枚举 字符串转换时,我使用别名,但方向相反:

    class Exported: public QObject {
        Q_OBJECT
    
    public:
        using QObject::QObject;
    
        enum class FOO { BAR };
    
        Q_ENUM(FOO)
    };
    
    using FOO = Exported::Foo;
    

    这让 moc 很开心并且是有效的 C++。缺点是您将Exported 的定义拉到您使用FOO 定义的每个范围内,并且您不能转发声明FOO

    1它是在 libclang 出现之前创建的,对于一些极端情况,一个完整的 C++ 解析器的实现成本将是极其不经济的。

    【讨论】:

    • 嗯,实际的问题是枚举来自一个库,所以我不能这样做。不管怎样,谢谢你。此外,对标准的引用是指 Qt 文档中可能遗漏了 declaration 的事实。就是这样。
    • @skypjack 好的,Qt 的文档可能会得到改进。我会把这个答案留给后代,即使它不能解决你的问题。
    • 当然,在一般情况下没问题,如果你可以同时控制类和枚举。
    • 如果你从那个库中获得了一个.h,其中只定义了枚举,你可以这样做 class Foo : public QObject { Q_OBJECT, #include &lt;stuff.h&gt;, Q_ENUM(MyEnum) }; ... 不是我建议它...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 2019-08-17
    • 2016-11-23
    • 2019-02-18
    • 2015-05-16
    • 2017-10-14
    相关资源
    最近更新 更多