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

问题描述 投票:0回答:3
  • 我有两个
    enum
    。它们位于相同的命名空间中,但头文件不同。
  • 为了使它们可用于 Qt 元类型系统,我尝试这样做:
//C1.h
#include <QObject>
namespace SW
{
Q_NAMESPACE
enum class Enum1 {A, B};
Q_ENUM_NS(Enum1)
}
//C2.h
#include <QObject>
namespace SW
{
Q_NAMESPACE
enum class Enum2 {A, B};
Q_ENUM_NS(Enum2)
}
//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();
}
  • 通过上面的内容,我得到重复的符号链接器错误。因为
    moc_C1.o
    moc_C2.o
    都定义了由 staticMetaObject
     产生的 
    Q_NAMESPACE
  • 我发现两个标头中的命名空间都必须包含
    Q_NAMESPACE
    。否则 moc 会抱怨“错误:命名空间声明缺少 Q_NAMESPACE 宏。”
  • 如果我只有 C1.h 或 C2.h 之一,它就可以正常构建和工作。
  • 如果我将 C2.h 的内容移动到 C1.h,它也可以工作,并且会打印:
me1 valid: true
me2 valid: true
  • 如果我将 C2.h 的内容移至 main.cpp(带或不带
    Q_NAMESPACE
    ),它会编译但在运行时出现故障:
me1 valid: true
me2 valid: false

问题:是否无法将

Q_NAMESPACE
用于分布在多个文件上的命名空间?

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

    将我的枚举包含在 Q_OBJECT 或 Q_GADGET 类中
  • 将我的所有枚举都放在同一个文件中
c++ qt
3个回答
3
投票
官方 Qt 问题跟踪器中存在相应的问题:

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

简而言之,Qt 不支持多个头文件,每个头文件都有

Q_NAMESPACE

 宏。这是不可能的。

或者,您可以

(尽管我不建议)有一个中间文件结构,如下所示:

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

0
投票
令我非常失望的是,这是不可能的。

或者,

Verdigris 库。它完全兼容 Qt,并且无需调用 MOC 即可启用 Qt 的功能,因此您不会收到缺少 Q_NAMESPACE 的错误。

但是您需要在某些源文件中的 W_ENUM_NS 宏和 W_NAMESPACE_IMPL 中列出所有枚举值

//foo.h #pragma once #include "wobjectdefs.h" namespace lib { W_NAMESPACE(lib) enum class Foo { A, B, }; W_ENUM_NS(Foo, Foo::A, Foo::B) } // namespace lib

-

// bar.h #pragma once #include "foo.h" #include "wobjectdefs.h" namespace lib { enum class Bar { A, B, }; W_ENUM_NS(Bar, Bar::A, Bar::B) } // namespace lib

-

#include <QCoreApplication> #include <QDebug> #include "bar.h" #include "foo.h" #include "wobjectimpl.h" namespace lib { W_NAMESPACE_IMPL(lib) } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << lib::Bar::A; qDebug() << lib::Foo::A; return a.exec(); }
    

0
投票
解决方案是内联命名空间。

// file_1.h namespace A { inline namespace File1 { Q_NAMESPACE enum class E1{ ... }; Q_ENUM_NS(E1) } } // file_2.h namespace A { inline namespace File2 { Q_NAMESPACE enum class E2{ ... }; Q_ENUM_NS(E2) } }
    
© www.soinside.com 2019 - 2024. All rights reserved.