Q_ENUMS和使用声明无法一起使用

时间:2016-11-09 16:43:51

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

考虑以下类定义:

// 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

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

// 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_ENUM实际上是documentation(强调我的):

  

此宏使用元对象系统注册枚举类型。 必须放在具有Q_OBJECT或Q_GADGET宏的类中的枚举声明之后。

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

  

using声明将一组声明引入声明区域,其中出现using声明。

所以,我期待它也可以运作。无论如何,这可能是我个人的错误期望。

那说,有关如何处理这么不方便的任何建议吗? 如果在类中定义 enum ,我可以看到解决它的唯一方法是在类中定义另一个 enum 并且具有一对一的一对一它们之间的映射。
它确实远没有可维护性和有点乏味。

1 个答案:

答案 0 :(得分:1)

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

在我的代码中,当我想要moc生成枚举&lt; - &gt;字符串转换对我来说,我使用别名,但方向相反:

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 ++解析器的实现成本非常不经济。