Skip to content

Instantly share code, notes, and snippets.

@mwoehlke-kitware mwoehlke-kitware/ABOUT.rst Secret

Created Aug 28, 2019
Embed
What would you like to do?
Why inline namespaces are useful with Qt

This example demonstrates how inline namespaces can be used to work around the Qt limit that only allows Q_NAMESPACE to be used in a single header for a particular namespace.

Given a program with multiple enumerations, we would like:

  1. For each enumeration to belong to the same namespace.
  2. For each enumeration to be decorated with Q_ENUM_NS.
  3. For each enumeration to be defined in its own header.

Normally, it would not be possible to accomplish all of these goals. This is because, in order to use Q_ENUM_NS, a Q_NAMESPACE must appear in the same block. However, if Q_NAMESPACE appears in multiple headers, moc will generate a "different" meta-object for each instance, resulting in duplicate definition errors when we try to link the program, which breaks goal #3.

The usual work-around is to toss goal #3 and have one header that defines all enumerations in the namespace. However, this breaks locality; we would prefer for enumerations to be defined "near" the code that uses them, or at least to be able to break down the set of all enumerations into logical parts.

Another option is to put each enumeration in its own namespace. Normally, this would add unnecessary verbosity to the API... but this is where inline namespaces can save us. Because the contents of an inline namespace are added to the parent namespace, we can achieve a "soft" separation that is invisible to users of our API, but sufficient that each inline namespace has a distinct static meta-object, thus solving our duplicate definitions problem.

namespace example
{
#ifdef BROKEN
Q_NAMESPACE // generates frob::staticMetaObject in moc_bar.cpp
enum class bar { ... };
Q_ENUM_NS(bar)
#else
inline namespace bar_enums
{
Q_NAMESPACE // generates frob::bar_enums::staticMetaObject in moc_foo.cpp
enum class bar { ... };
Q_ENUM_NS(bar)
}
#endif
}
namespace example
{
#ifdef BROKEN
Q_NAMESPACE // generates frob::staticMetaObject in moc_foo.cpp
enum class foo { ... };
Q_ENUM_NS(foo)
#else
inline namespace foo_enums
{
Q_NAMESPACE // generates frob::foo_enums::staticMetaObject in moc_foo.cpp
enum class foo { ... };
Q_ENUM_NS(foo)
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.