3
  • 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
  • 699
  • 3
  • 12

2 Answers2

0

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
}
eyllanesc
  • 221,139
  • 17
  • 121
  • 189
ExaltedBagel
  • 472
  • 7
  • 11
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
  • 414
  • 3
  • 13