Q_NAMESPACE across multiple files
-
Hey, I have a folder called common/enums in which I want to store some enums which I also want to register to QML. I am using Q_NAMESPACE combined with Q_ENUM_NS to do this. This works just fine for one enum, but when adding another, I am getting this error:
In file included from /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/mocs_compilation.cpp:3: /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_common_mocked_namespace.cpp:24:8: error: redefinition of ‘struct qt_meta_stringdata_application_t’ 24 | struct qt_meta_stringdata_application_t { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/mocs_compilation.cpp:2: /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_book_operation_status.cpp:24:8: note: previous definition of ‘struct qt_meta_stringdata_application_t’ 24 | struct qt_meta_stringdata_application_t { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_common_mocked_namespace.cpp:33:47: error: redefinition of ‘const qt_meta_stringdata_application_t qt_meta_stringdata_application’ 33 | static const qt_meta_stringdata_application_t qt_meta_stringdata_application = { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_book_operation_status.cpp:33:47: note: ‘const qt_meta_stringdata_application_t qt_meta_stringdata_application’ previously defined here 33 | static const qt_meta_stringdata_application_t qt_meta_stringdata_application = { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_common_mocked_namespace.cpp:42:19: error: redefinition of ‘const uint qt_meta_data_application []’ 42 | static const uint qt_meta_data_application[] = { | ^~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_book_operation_status.cpp:53:19: note: ‘const uint qt_meta_data_application [34]’ previously defined here 53 | static const uint qt_meta_data_application[] = { | ^~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_common_mocked_namespace.cpp:58:38: error: redefinition of ‘const QMetaObject application::staticMetaObject’ 58 | QT_INIT_METAOBJECT const QMetaObject application::staticMetaObject = { { | ^~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_book_operation_status.cpp:81:38: note: ‘const QMetaObject application::staticMetaObject’ previously defined here 81 | QT_INIT_METAOBJECT const QMetaObject application::staticMetaObject = { { | ^~~~~~~~~~~ In file included from /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/mocs_compilation.cpp:4: /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_settings_keys.cpp:24:8: error: redefinition of ‘struct qt_meta_stringdata_application_t’ 24 | struct qt_meta_stringdata_application_t { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_book_operation_status.cpp:24:8: note: previous definition of ‘struct qt_meta_stringdata_application_t’ 24 | struct qt_meta_stringdata_application_t { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_settings_keys.cpp:33:47: error: redefinition of ‘const qt_meta_stringdata_application_t qt_meta_stringdata_application’ 33 | static const qt_meta_stringdata_application_t qt_meta_stringdata_application = { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_book_operation_status.cpp:33:47: note: ‘const qt_meta_stringdata_application_t qt_meta_stringdata_application’ previously defined here 33 | static const qt_meta_stringdata_application_t qt_meta_stringdata_application = { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_settings_keys.cpp:57:19: error: redefinition of ‘const uint qt_meta_data_application []’ 57 | static const uint qt_meta_data_application[] = { | ^~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_book_operation_status.cpp:53:19: note: ‘const uint qt_meta_data_application [34]’ previously defined here 53 | static const uint qt_meta_data_application[] = { | ^~~~~~~~~~~~~~~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_settings_keys.cpp:88:38: error: redefinition of ‘const QMetaObject application::staticMetaObject’ 88 | QT_INIT_METAOBJECT const QMetaObject application::staticMetaObject = { { | ^~~~~~~~~~~ /home/creapermann/Programming/Etovex/Librum/build-Debug/src/application/application_autogen/QVJXAE3BGF/moc_book_operation_status.cpp:81:38: note: ‘const QMetaObject application::staticMetaObject’ previously defined here 81 | QT_INIT_METAOBJECT const QMetaObject application::staticMetaObject = { { | ^~~~~~~~~~~ [35/87] Building CXX object src/application/core/gene...ularGenerator_comicbook.dir/generator_comicbook.cpp.o ninja: build stopped: subcommand failed.
I known that this is a known bug (or problem), since there are multiple bug reports for it (https://bugreports.qt.io/browse/QTBUG-68611).
Non the less, is there a work around so that one is able to have enums in the same namespace registered to QML?
My classes both look like this (Just with a different enum name):namespace application { Q_NAMESPACE enum class BookOperationStatus { Success, OpeningBookFailed, BookDoesNotExist, PropertyDoesNotExist, TagDoesNotExist, TagAlreadyExists, OperationFailed }; Q_ENUM_NS(BookOperationStatus) } // namespace application
Thanks in advance
-
@Creaperdown said in Q_NAMESPACE across multiple files:
Non the less, is there a work around so that one is able to have enums in the same namespace registered to QML?
Perhaps this will work for you.
Group all the QObject-related declarations into a single header and put nothing QObject related in the others. Use a little macro magic to get all the enum declarations inside a single namespace { } block to work aroundmoc
not having a full C++ parser.#ifndef ENUMDECL_H #define ENUMDECL_H #include <QObject> namespace application { #include "enum1.h" #include "enum2.h" Q_NAMESPACE Q_ENUM_NS(Enum1) Q_ENUM_NS(Enum2) } #endif // ENUMDECL_H
#ifndef ENUM1_H #define ENUM1_H #ifndef ENUMDECL_H namespace application { #endif enum class Enum1 { Enum1_Value1, Enum1_Value2, Enum1_Value3 }; #ifndef ENUMDECL_H } // namespace application #endif #endif // ENUM1_H
#ifndef ENUM2_H #define ENUM2_H #ifndef ENUMDECL_H namespace application { #endif enum class Enum2 { Enum2_Value1, Enum2_Value2, Enum2_Value3 }; #ifndef ENUMDECL_H } // namespace application #endif #endif // ENUM2_H
HEADERS += \ enumdecl.h
You will get just the one moc-related bunch of static structures in your code.
Edit: Not exactly sure how it will go with CMake
-
@Creaperdown said in Q_NAMESPACE across multiple files:
Non the less, is there a work around so that one is able to have enums in the same namespace registered to QML?
Perhaps this will work for you.
Group all the QObject-related declarations into a single header and put nothing QObject related in the others. Use a little macro magic to get all the enum declarations inside a single namespace { } block to work aroundmoc
not having a full C++ parser.#ifndef ENUMDECL_H #define ENUMDECL_H #include <QObject> namespace application { #include "enum1.h" #include "enum2.h" Q_NAMESPACE Q_ENUM_NS(Enum1) Q_ENUM_NS(Enum2) } #endif // ENUMDECL_H
#ifndef ENUM1_H #define ENUM1_H #ifndef ENUMDECL_H namespace application { #endif enum class Enum1 { Enum1_Value1, Enum1_Value2, Enum1_Value3 }; #ifndef ENUMDECL_H } // namespace application #endif #endif // ENUM1_H
#ifndef ENUM2_H #define ENUM2_H #ifndef ENUMDECL_H namespace application { #endif enum class Enum2 { Enum2_Value1, Enum2_Value2, Enum2_Value3 }; #ifndef ENUMDECL_H } // namespace application #endif #endif // ENUM2_H
HEADERS += \ enumdecl.h
You will get just the one moc-related bunch of static structures in your code.
Edit: Not exactly sure how it will go with CMake
This post is deleted! -
@Creaperdown said in Q_NAMESPACE across multiple files:
Non the less, is there a work around so that one is able to have enums in the same namespace registered to QML?
Perhaps this will work for you.
Group all the QObject-related declarations into a single header and put nothing QObject related in the others. Use a little macro magic to get all the enum declarations inside a single namespace { } block to work aroundmoc
not having a full C++ parser.#ifndef ENUMDECL_H #define ENUMDECL_H #include <QObject> namespace application { #include "enum1.h" #include "enum2.h" Q_NAMESPACE Q_ENUM_NS(Enum1) Q_ENUM_NS(Enum2) } #endif // ENUMDECL_H
#ifndef ENUM1_H #define ENUM1_H #ifndef ENUMDECL_H namespace application { #endif enum class Enum1 { Enum1_Value1, Enum1_Value2, Enum1_Value3 }; #ifndef ENUMDECL_H } // namespace application #endif #endif // ENUM1_H
#ifndef ENUM2_H #define ENUM2_H #ifndef ENUMDECL_H namespace application { #endif enum class Enum2 { Enum2_Value1, Enum2_Value2, Enum2_Value3 }; #ifndef ENUMDECL_H } // namespace application #endif #endif // ENUM2_H
HEADERS += \ enumdecl.h
You will get just the one moc-related bunch of static structures in your code.
Edit: Not exactly sure how it will go with CMake
@ChrisW67 Thanks, this fixes it. Do you think there might be a way without the macro magic here though?
-
A solution I came up with, is putting every enum into its own unique namespace to avoid the MOC duplication problems:
#pragma once #include <QObject> // Each enum needs to be in a separate namespace due to a Qt bug reported at: // https://bugreports.qt.io/browse/QTBUG-81792 // // This causes not being able to register multiple enums to the Qt type system // and to QML (Q_NAMESPACE and Q_ENUM_NS), if they are in the same namespace. // The work around is to create a separate namespace for each enum. namespace application::setting_keys { Q_NAMESPACE enum class SettingKeys { Theme, PageSpacing, DisplayBookTitleInTitlebar, LayoutDirection, DisplayMode, PageTransition, DefaultZoom, SmoothScrolling, LoopAfterLastPage, CursorMode }; Q_ENUM_NS(SettingKeys) } // namespace application::setting_keys // Because the enum shouldn't be in a separate namespace in the first place, // make the namespace available to all of its users to avoid syntactic clutter. using namespace application::setting_keys;
If anyone finds a better solution, please let me know.