Warm tip: This article is reproduced from stackoverflow.com, please click
c++ QT

Qt C++: Multiple Q_NAMESPACE for the same namespace in different files

发布于 2020-04-08 09:29:33
  • I have two enums. They are in the same namespace, but different header files.
  • To make them available to Qt meta type system, I try this:
//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();
}
  • With the above I get duplicate symbol linker error. Because both moc_C1.o and moc_C2.o defined the staticMetaObject that result from Q_NAMESPACE
  • I found that namespace in both headers must contain Q_NAMESPACE. Otherwise moc complains "Error: Namespace declaration lacks Q_NAMESPACE macro."
  • If I have only one of C1.h or C2.h, it builds and works fine.
  • If I move content of C2.h to C1.h, it also works, and would print:
me1 valid: true
me2 valid: true
  • If I move content of C2.h to main.cpp (with or without the Q_NAMESPACE), it compiles but malfunctions at runtime:
me1 valid: true
me2 valid: false

Question: is there no way to use Q_NAMESPACE for a namespace spread over multiple files?

Ways that work around this problem I can think of:

  • Enclose my enum in Q_OBJECT or Q_GADGET class
  • Have all my enum in the same file
Questioner
twj
Viewed
118
138k 2020-02-01 09:38

It seems to be a known bug according to their issue tracker QTBUG-68611

We will have to live with this limitation until it is solved.

Alternatively, you could (although I do not advise) have an in-between with a file structure such as this:

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