Qt C++:不同文件中相同命名空间的多个 Q_NAMESPACE

twj*_*twj 6 c++ qt

  • 我有两个enum。它们位于相同的命名空间中,但头文件不同。
  • 为了使它们可用于 Qt 元类型系统,我尝试这样做:
//C1.h
#include <QObject>
namespace SW
{
Q_NAMESPACE
enum class Enum1 {A, B};
Q_ENUM_NS(Enum1)
}
Run Code Online (Sandbox Code Playgroud)
//C2.h
#include <QObject>
namespace SW
{
Q_NAMESPACE
enum class Enum2 {A, B};
Q_ENUM_NS(Enum2)
}
Run Code Online (Sandbox Code Playgroud)
//main.c
#include <QDebug>
#include <QMetaEnum>

#include "C1.h"
#include "C2.h"

int main(int argc, char *argv[]) {
    auto me1 = QMetaEnum::fromType<SW::Enum1>();
    qDebug() << "me1 valid:" << me1.isValid();

    auto me2 = QMetaEnum::fromType<SW::Enum2>();
    qDebug() << "me2 valid:" << me2.isValid();
}
Run Code Online (Sandbox Code Playgroud)
  • 通过上面的内容,我得到了重复的符号链接器错误。因为 和moc_C1.omoc_C2.o定义了staticMetaObject结果Q_NAMESPACE
  • 我发现两个标头中的命名空间都必须包含Q_NAMESPACE. 否则 moc 会抱怨“错误:命名空间声明缺少 Q_NAMESPACE 宏。”
  • 如果我只有 C1.h 或 C2.h 之一,它就可以正常构建和工作。
  • 如果我将 C2.h 的内容移动到 C1.h,它也可以工作,并且会打印:
me1 valid: true
me2 valid: true
Run Code Online (Sandbox Code Playgroud)
  • 如果我将 C2.h 的内容移动到 main.cpp (带或不带Q_NAMESPACE),它会编译但在运行时出现故障:
me1 valid: true
me2 valid: false
Run Code Online (Sandbox Code Playgroud)

问题:是否没有办法使用Q_NAMESPACE分布在多个文件上的命名空间?

我能想到的解决这个问题的方法

  • 将我的枚举包含在 Q_OBJECT 或 Q_GADGET 类中
  • 将我所有的枚举放在同一个文件中

小智 2

官方 Qt 问题跟踪器QTBUG-68611中有相应的问题。然而,该问题因超出范围而被关闭,因为由于 Qt 元对象编译器 (moc) 的设计,对此无能为力。

简而言之,Qt 不能支持多个头文件,每个头文件都有Q_NAMESPACE宏。这不可能。

或者,您可以(尽管我不建议)在文件结构之间设置一个中间层,如下所示:

// internal/C1.h
#include <QObject>
enum class Enum1 {A, B};
Q_ENUM_NS(Enum1)
Run Code Online (Sandbox Code Playgroud)
//internal/C2.h
#include <QObject>
enum class Enum2 {A, B};
Q_ENUM_NS(Enum1)
Run Code Online (Sandbox Code Playgroud)
// C.h
#include <QObject>
namespace SW
{
Q_NAMESPACE
#include internal/C1.h
#include internal/C2.h
}
Run Code Online (Sandbox Code Playgroud)