6
  • 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
twj
  • 759
  • 5
  • 12

2 Answers2

1

There is a corresponding issue in the official Qt issue tracker at QTBUG-68611. However the issue is closed there as being out of scope, because due to the design of the Qt meta object compiler (moc), there is nothing that can be done about it.

In short, Qt can not support multiple header files that each have the Q_NAMESPACE macro. It is not possible.

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
}
emmenlau
  • 958
  • 12
  • 20
ExaltedBagel
  • 582
  • 5
  • 14
0

To my great disappointment, it is not possible.

Alternatively, Verdigris library. It fully Qt compatible and enable Qt's facilities without the need to invoke MOC, so you won't get the error on missing Q_NAMESPACE.

But you will need to list all your enum value in W_ENUM_NS macro and W_NAMESPACE_IMPL in some source file

//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();
}
Zak
  • 464
  • 3
  • 13