diff --git a/src/corelib/global/qtclasshelpermacros.h b/src/corelib/global/qtclasshelpermacros.h index 0b7f943ea73..952d3827507 100644 --- a/src/corelib/global/qtclasshelpermacros.h +++ b/src/corelib/global/qtclasshelpermacros.h @@ -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); } diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp index e98bdacd44a..7dd027160ed 100644 --- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp +++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp @@ -42,6 +42,27 @@ static_assert(!q_is_adl_swappable_v); 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::isRelocatable); static_assert( QTypeInfo::isRelocatable); + static_assert( QTypeInfo::isRelocatable); + static_assert( QTypeInfo::isRelocatable); + static_assert( QTypeInfo::isRelocatable); + static_assert( QTypeInfo::isRelocatable); + static_assert( QTypeInfo::isRelocatable); } void tst_QGlobal::qDeclareSharedMakesTheTypeAdlSwappable() { static_assert(!q_is_adl_swappable_v); static_assert( q_is_adl_swappable_v); + static_assert( q_is_adl_swappable_v); + static_assert( q_is_adl_swappable_v); + static_assert( q_is_adl_swappable_v); + static_assert( q_is_adl_swappable_v); + static_assert( q_is_adl_swappable_v); #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 }