Long live Q_DECLARE_SHARED_NS!

We used to mark Q_DECLARE_SHARED all our value classes in Qt 4 times,
but since many Qt types these days live in nested namespaces that
macro, which only works in the QT_NAMESPACE, has become less useful.

As we use it in more and more places and eventually add more
responsibilities to it, we don't want every module to define its
version by hand, like QT3D_DECLARE_SHARED did in 2016 already.

So add two namespace-aware versions of Q_DECLARE_SHARED, to be used
inside or outside nested namespaces.

Extend the test.

Despite the name, this is not a public macro.

Found missing Q_D_S in API-review, so picking this to 6.8 to aid with
fixing the 6.8 API.

Change-Id: I367ca0d5b005b64090de44f7b7541d8639f9a4e0
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
(cherry picked from commit 37b2b2ea4ef3cf494d23885de186a9519763e744)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2024-07-03 15:03:08 +02:00 committed by Qt Cherry-pick Bot
parent dc3b7d2203
commit 19fbb338b8
2 changed files with 81 additions and 0 deletions

View File

@ -141,10 +141,55 @@ namespace QtPrivate {
where 'type' is the name of the type to specialize. NOTE: shared
types must define a member-swap, and be defined in the same
namespace as Qt for this to work.
For types defined in a namespace within QT_NAMESPACE, use
Q_DECLARE_SHARED_NS/_EXT instead. The _NS macro needs to be placed
inside the nested namespace:
namespace ns {
// ~~~ type defined here ~~~
Q_DECLARE_SHARED_NS(ns, type)
}
while the _NS_EXT macro goes into the QT_NAMESPACE, outside any
nested namespaces:
namespace ns {
// ~~~ type defined here ~~~
}
Q_DECLARE_SHARED_NS_EXT(ns, type)
The latter then also works for more deeply-nested namespaces:
Q_DECLARE_SHARED_NS_EXT(ns1::ns2, type)
Q_DECLARE_SHARED_NS does, too, if all namespaces were opened in one statement:
namespace ns1::ns2 {
Q_DECLARE_SHARED_NS(ns1::ns2, type);
}
*/
#define Q_DECLARE_SHARED(TYPE) \
QT_DECLARE_ADL_SWAP(TYPE) \
Q_DECLARE_TYPEINFO(TYPE, Q_RELOCATABLE_TYPE); \
/* end */
#define Q_DECLARE_SHARED_NS(NS, TYPE) \
QT_DECLARE_ADL_SWAP(TYPE) \
} /* namespace NS */ \
Q_DECLARE_TYPEINFO(NS :: TYPE, Q_RELOCATABLE_TYPE); \
namespace NS { \
/* end */
#define Q_DECLARE_SHARED_NS_EXT(NS, TYPE) \
namespace NS { \
QT_DECLARE_ADL_SWAP(TYPE) \
} /* namespace NS */ \
Q_DECLARE_TYPEINFO(NS :: TYPE, Q_RELOCATABLE_TYPE); \
/* end */
#define QT_DECLARE_ADL_SWAP(TYPE) \
inline void swap(TYPE &value1, TYPE &value2) \
noexcept(noexcept(value1.swap(value2))) \
{ value1.swap(value2); }

View File

@ -42,6 +42,27 @@ static_assert(!q_is_adl_swappable_v<NotQDeclareShared>);
MAKE_CLASS(Terry); // R.I.P.
Q_DECLARE_SHARED(Terry)
namespace Discworld {
MAKE_CLASS(Librarian);
Q_DECLARE_SHARED_NS(Discworld, Librarian)
MAKE_CLASS(Baggage);
namespace AnkhMorpork {
MAKE_CLASS(Vetinari);
// Q_DECLARE_SHARED_NS only work on a single nesting level
namespace CityWatch {
MAKE_CLASS(Vimes);
} // namespace CityWatch
} // namespace AnkhMorpork
} // namespace Discworld
Q_DECLARE_SHARED_NS_EXT(Discworld, Baggage)
Q_DECLARE_SHARED_NS_EXT(Discworld::AnkhMorpork, Vetinari)
Q_DECLARE_SHARED_NS_EXT(Discworld::AnkhMorpork::CityWatch, Vimes)
// but Q_DECLARE_SHARED_NS works if all namespaces are opened in one statement:
namespace Discworld::AnkhMorpork {
MAKE_CLASS(Leonardo);
Q_DECLARE_SHARED_NS(Discworld::AnkhMorpork, Leonardo)
} // namespace Discworld::AnkhMorpork
#undef MAKE_CLASS
QT_END_NAMESPACE
@ -432,12 +453,22 @@ void tst_QGlobal::qDeclareSharedMarksTheTypeRelocatable()
{
static_assert(!QTypeInfo<QT_PREPEND_NAMESPACE(NotQDeclareShared)>::isRelocatable);
static_assert( QTypeInfo<QT_PREPEND_NAMESPACE(Terry)>::isRelocatable);
static_assert( QTypeInfo<QT_PREPEND_NAMESPACE(Discworld::Librarian)>::isRelocatable);
static_assert( QTypeInfo<QT_PREPEND_NAMESPACE(Discworld::Baggage)>::isRelocatable);
static_assert( QTypeInfo<QT_PREPEND_NAMESPACE(Discworld::AnkhMorpork::Vetinari)>::isRelocatable);
static_assert( QTypeInfo<QT_PREPEND_NAMESPACE(Discworld::AnkhMorpork::Leonardo)>::isRelocatable);
static_assert( QTypeInfo<QT_PREPEND_NAMESPACE(Discworld::AnkhMorpork::CityWatch::Vimes)>::isRelocatable);
}
void tst_QGlobal::qDeclareSharedMakesTheTypeAdlSwappable()
{
static_assert(!q_is_adl_swappable_v<QT_PREPEND_NAMESPACE(NotQDeclareShared)>);
static_assert( q_is_adl_swappable_v<QT_PREPEND_NAMESPACE(Terry)>);
static_assert( q_is_adl_swappable_v<QT_PREPEND_NAMESPACE(Discworld::Librarian)>);
static_assert( q_is_adl_swappable_v<QT_PREPEND_NAMESPACE(Discworld::Baggage)>);
static_assert( q_is_adl_swappable_v<QT_PREPEND_NAMESPACE(Discworld::AnkhMorpork::Vetinari)>);
static_assert( q_is_adl_swappable_v<QT_PREPEND_NAMESPACE(Discworld::AnkhMorpork::Leonardo)>);
static_assert( q_is_adl_swappable_v<QT_PREPEND_NAMESPACE(Discworld::AnkhMorpork::CityWatch::Vimes)>);
#define CHECK(Class) do { \
using C = QT_PREPEND_NAMESPACE(Class); \
@ -451,6 +482,11 @@ void tst_QGlobal::qDeclareSharedMakesTheTypeAdlSwappable()
QCOMPARE_EQ(rhs.s, "lhs"); \
} while (false)
CHECK(Terry);
CHECK(Discworld::Librarian);
CHECK(Discworld::Baggage);
CHECK(Discworld::AnkhMorpork::Vetinari);
CHECK(Discworld::AnkhMorpork::Leonardo);
CHECK(Discworld::AnkhMorpork::CityWatch::Vimes);
#undef CHECK
}