summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qtypeinfo.h17
-rw-r--r--src/corelib/io/qdebug.h16
-rw-r--r--src/corelib/serialization/qdatastream.h31
-rw-r--r--src/corelib/tools/qhash.h4
-rw-r--r--src/corelib/tools/qlist.h12
-rw-r--r--src/corelib/tools/qmap.h8
-rw-r--r--src/corelib/tools/qset.h4
-rw-r--r--tests/auto/corelib/tools/collections/tst_collections.cpp144
8 files changed, 204 insertions, 32 deletions
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h
index 58f20b7be4..2729217aab 100644
--- a/src/corelib/global/qtypeinfo.h
+++ b/src/corelib/global/qtypeinfo.h
@@ -335,17 +335,29 @@ struct has_operator_equal : detail::expand_operator_equal<T> {};
template<typename T>
inline constexpr bool has_operator_equal_v = has_operator_equal<T>::value;
+template <typename Container, typename T>
+using has_operator_equal_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_operator_equal<T>>;
+
template<typename T>
struct has_operator_less_than : detail::expand_operator_less_than<T> {};
template<typename T>
inline constexpr bool has_operator_less_than_v = has_operator_less_than<T>::value;
+template <typename Container, typename T>
+using has_operator_less_than_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_operator_less_than<T>>;
+
template <typename ...T>
using compare_eq_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal<T>...>, bool>;
+template <typename Container, typename ...T>
+using compare_eq_result_container = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal_container<Container, T>...>, bool>;
+
template <typename ...T>
using compare_lt_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than<T>...>, bool>;
+template <typename Container, typename ...T>
+using compare_lt_result_container = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than_container<Container, T>...>, bool>;
+
namespace detail {
template<typename T>
@@ -363,6 +375,9 @@ struct has_ostream_operator<Stream, T, std::void_t<decltype(detail::reference<St
template <typename Stream, typename T>
inline constexpr bool has_ostream_operator_v = has_ostream_operator<Stream, T>::value;
+template <typename Stream, typename Container, typename T>
+using has_ostream_operator_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_ostream_operator<Stream, T>>;
+
template <typename Stream, typename, typename = void>
struct has_istream_operator : std::false_type {};
template <typename Stream, typename T>
@@ -370,6 +385,8 @@ struct has_istream_operator<Stream, T, std::void_t<decltype(detail::reference<St
: std::true_type {};
template <typename Stream, typename T>
inline constexpr bool has_istream_operator_v = has_istream_operator<Stream, T>::value;
+template <typename Stream, typename Container, typename T>
+using has_istream_operator_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_istream_operator<Stream, T>>;
template <typename Stream, typename T>
inline constexpr bool has_stream_operator_v = has_ostream_operator_v<Stream, T> && has_istream_operator_v<Stream, T>;
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index 29da386c1b..d1c2fea494 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -243,8 +243,12 @@ template<typename ...T>
using QDebugIfHasDebugStream =
std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator<QDebug, T>...>, QDebug>;
+template<typename Container, typename ...T>
+using QDebugIfHasDebugStreamContainer =
+ std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator_container<QDebug, Container, T>...>, QDebug>;
+
template<typename T>
-inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QList<T> &vec)
+inline QDebugIfHasDebugStreamContainer<QList<T>, T> operator<<(QDebug debug, const QList<T> &vec)
{
return QtPrivate::printSequentialContainer(debug, "QList", vec);
}
@@ -274,25 +278,25 @@ inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::multim
}
template <class Key, class T>
-inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const QMap<Key, T> &map)
+inline QDebugIfHasDebugStreamContainer<QMap<Key, T>, Key, T> operator<<(QDebug debug, const QMap<Key, T> &map)
{
return QtPrivate::printAssociativeContainer(debug, "QMap", map);
}
template <class Key, class T>
-inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const QMultiMap<Key, T> &map)
+inline QDebugIfHasDebugStreamContainer<QMultiMap<Key, T>, Key, T> operator<<(QDebug debug, const QMultiMap<Key, T> &map)
{
return QtPrivate::printAssociativeContainer(debug, "QMultiMap", map);
}
template <class Key, class T>
-inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const QHash<Key, T> &hash)
+inline QDebugIfHasDebugStreamContainer<QHash<Key, T>, Key, T> operator<<(QDebug debug, const QHash<Key, T> &hash)
{
return QtPrivate::printAssociativeContainer(debug, "QHash", hash);
}
template <class Key, class T>
-inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const QMultiHash<Key, T> &hash)
+inline QDebugIfHasDebugStreamContainer<QMultiHash<Key, T>, Key, T> operator<<(QDebug debug, const QMultiHash<Key, T> &hash)
{
return QtPrivate::printAssociativeContainer(debug, "QMultiHash", hash);
}
@@ -306,7 +310,7 @@ inline QDebugIfHasDebugStream<T1, T2> operator<<(QDebug debug, const std::pair<T
}
template <typename T>
-inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QSet<T> &set)
+inline QDebugIfHasDebugStreamContainer<QSet<T>, T> operator<<(QDebug debug, const QSet<T> &set)
{
return QtPrivate::printSequentialContainer(debug, "QSet", set);
}
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index 523dabfdc6..1ec9704a6a 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.h
@@ -351,9 +351,16 @@ QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c)
template<typename ...T>
using QDataStreamIfHasOStreamOperators =
std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator<QDataStream, T>...>, QDataStream &>;
+template<typename Container, typename ...T>
+using QDataStreamIfHasOStreamOperatorsContainer =
+ std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator_container<QDataStream, Container, T>...>, QDataStream &>;
+
template<typename ...T>
using QDataStreamIfHasIStreamOperators =
std::enable_if_t<std::conjunction_v<QTypeTraits::has_istream_operator<QDataStream, T>...>, QDataStream &>;
+template<typename Container, typename ...T>
+using QDataStreamIfHasIStreamOperatorsContainer =
+ std::enable_if_t<std::conjunction_v<QTypeTraits::has_istream_operator_container<QDataStream, Container, T>...>, QDataStream &>;
/*****************************************************************************
QDataStream inline functions
@@ -425,74 +432,74 @@ operator>>(QDataStream &s, T &t)
{ return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t); }
template<typename T>
-inline QDataStreamIfHasIStreamOperators<T> operator>>(QDataStream &s, QList<T> &v)
+inline QDataStreamIfHasIStreamOperatorsContainer<QList<T>, T> operator>>(QDataStream &s, QList<T> &v)
{
return QtPrivate::readArrayBasedContainer(s, v);
}
template<typename T>
-inline QDataStreamIfHasOStreamOperators<T> operator<<(QDataStream &s, const QList<T> &v)
+inline QDataStreamIfHasOStreamOperatorsContainer<QList<T>, T> operator<<(QDataStream &s, const QList<T> &v)
{
return QtPrivate::writeSequentialContainer(s, v);
}
template <typename T>
-inline QDataStreamIfHasIStreamOperators<T> operator>>(QDataStream &s, QSet<T> &set)
+inline QDataStreamIfHasIStreamOperatorsContainer<QSet<T>, T> operator>>(QDataStream &s, QSet<T> &set)
{
return QtPrivate::readListBasedContainer(s, set);
}
template <typename T>
-inline QDataStreamIfHasOStreamOperators<T> operator<<(QDataStream &s, const QSet<T> &set)
+inline QDataStreamIfHasOStreamOperatorsContainer<QSet<T>, T> operator<<(QDataStream &s, const QSet<T> &set)
{
return QtPrivate::writeSequentialContainer(s, set);
}
template <class Key, class T>
-inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QHash<Key, T> &hash)
+inline QDataStreamIfHasIStreamOperatorsContainer<QHash<Key, T>, Key, T> operator>>(QDataStream &s, QHash<Key, T> &hash)
{
return QtPrivate::readAssociativeContainer(s, hash);
}
template <class Key, class T>
-inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QHash<Key, T> &hash)
+inline QDataStreamIfHasOStreamOperatorsContainer<QHash<Key, T>, Key, T> operator<<(QDataStream &s, const QHash<Key, T> &hash)
{
return QtPrivate::writeAssociativeContainer(s, hash);
}
template <class Key, class T>
-inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QMultiHash<Key, T> &hash)
+inline QDataStreamIfHasIStreamOperatorsContainer<QMultiHash<Key, T>, Key, T> operator>>(QDataStream &s, QMultiHash<Key, T> &hash)
{
return QtPrivate::readAssociativeContainer(s, hash);
}
template <class Key, class T>
-inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QMultiHash<Key, T> &hash)
+inline QDataStreamIfHasOStreamOperatorsContainer<QMultiHash<Key, T>, Key, T> operator<<(QDataStream &s, const QMultiHash<Key, T> &hash)
{
return QtPrivate::writeAssociativeMultiContainer(s, hash);
}
template <class Key, class T>
-inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QMap<Key, T> &map)
+inline QDataStreamIfHasIStreamOperatorsContainer<QMap<Key, T>, Key, T> operator>>(QDataStream &s, QMap<Key, T> &map)
{
return QtPrivate::readAssociativeContainer(s, map);
}
template <class Key, class T>
-inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QMap<Key, T> &map)
+inline QDataStreamIfHasOStreamOperatorsContainer<QMap<Key, T>, Key, T> operator<<(QDataStream &s, const QMap<Key, T> &map)
{
return QtPrivate::writeAssociativeContainer(s, map);
}
template <class Key, class T>
-inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QMultiMap<Key, T> &map)
+inline QDataStreamIfHasIStreamOperatorsContainer<QMultiMap<Key, T>, Key, T> operator>>(QDataStream &s, QMultiMap<Key, T> &map)
{
return QtPrivate::readAssociativeContainer(s, map);
}
template <class Key, class T>
-inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QMultiMap<Key, T> &map)
+inline QDataStreamIfHasOStreamOperatorsContainer<QMultiMap<Key, T>, Key, T> operator<<(QDataStream &s, const QMultiMap<Key, T> &map)
{
return QtPrivate::writeAssociativeMultiContainer(s, map);
}
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 38f23d822f..9145891faf 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -820,7 +820,7 @@ public:
void swap(QHash &other) noexcept { qSwap(d, other.d); }
template <typename U = T>
- QTypeTraits::compare_eq_result<U> operator==(const QHash &other) const noexcept
+ QTypeTraits::compare_eq_result_container<QHash, U> operator==(const QHash &other) const noexcept
{
if (d == other.d)
return true;
@@ -836,7 +836,7 @@ public:
return true;
}
template <typename U = T>
- QTypeTraits::compare_eq_result<U> operator!=(const QHash &other) const noexcept
+ QTypeTraits::compare_eq_result_container<QHash, U> operator!=(const QHash &other) const noexcept
{ return !(*this == other); }
inline qsizetype size() const noexcept { return d ? qsizetype(d->size) : 0; }
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index ddce07bbb7..0329dd37da 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -290,7 +290,7 @@ public:
void swap(QList<T> &other) noexcept { qSwap(d, other.d); }
template <typename U = T>
- QTypeTraits::compare_eq_result<U> operator==(const QList &other) const
+ QTypeTraits::compare_eq_result_container<QList, U> operator==(const QList &other) const
{
if (size() != other.size())
return false;
@@ -301,13 +301,13 @@ public:
return d->compare(begin(), other.begin(), size());
}
template <typename U = T>
- QTypeTraits::compare_eq_result<U> operator!=(const QList &other) const
+ QTypeTraits::compare_eq_result_container<QList, U> operator!=(const QList &other) const
{
return !(*this == other);
}
template <typename U = T>
- QTypeTraits::compare_lt_result<U> operator<(const QList &other) const
+ QTypeTraits::compare_lt_result_container<QList, U> operator<(const QList &other) const
noexcept(noexcept(std::lexicographical_compare<typename QList<U>::const_iterator,
typename QList::const_iterator>(
std::declval<QList<U>>().begin(), std::declval<QList<U>>().end(),
@@ -318,21 +318,21 @@ public:
}
template <typename U = T>
- QTypeTraits::compare_lt_result<U> operator>(const QList &other) const
+ QTypeTraits::compare_lt_result_container<QList, U> operator>(const QList &other) const
noexcept(noexcept(other < std::declval<QList<U>>()))
{
return other < *this;
}
template <typename U = T>
- QTypeTraits::compare_lt_result<U> operator<=(const QList &other) const
+ QTypeTraits::compare_lt_result_container<QList, U> operator<=(const QList &other) const
noexcept(noexcept(other < std::declval<QList<U>>()))
{
return !(other < *this);
}
template <typename U = T>
- QTypeTraits::compare_lt_result<U> operator>=(const QList &other) const
+ QTypeTraits::compare_lt_result_container<QList, U> operator>=(const QList &other) const
noexcept(noexcept(std::declval<QList<U>>() < other))
{
return !(*this < other);
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index d5f6b91ba8..57a964f29f 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -277,7 +277,7 @@ public:
}
template <typename AKey = Key, typename AT = T> friend
- QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMap &lhs, const QMap &rhs)
+ QTypeTraits::compare_eq_result_container<QMap, AKey, AT> operator==(const QMap &lhs, const QMap &rhs)
{
if (lhs.d == rhs.d)
return true;
@@ -288,7 +288,7 @@ public:
}
template <typename AKey = Key, typename AT = T> friend
- QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMap &lhs, const QMap &rhs)
+ QTypeTraits::compare_eq_result_container<QMap, AKey, AT> operator!=(const QMap &lhs, const QMap &rhs)
{
return !(lhs == rhs);
}
@@ -905,7 +905,7 @@ public:
}
template <typename AKey = Key, typename AT = T> friend
- QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMultiMap &lhs, const QMultiMap &rhs)
+ QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> operator==(const QMultiMap &lhs, const QMultiMap &rhs)
{
if (lhs.d == rhs.d)
return true;
@@ -916,7 +916,7 @@ public:
}
template <typename AKey = Key, typename AT = T> friend
- QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMultiMap &lhs, const QMultiMap &rhs)
+ QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> operator!=(const QMultiMap &lhs, const QMultiMap &rhs)
{
return !(lhs == rhs);
}
diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h
index 681ce9cbe2..565b8b5691 100644
--- a/src/corelib/tools/qset.h
+++ b/src/corelib/tools/qset.h
@@ -72,10 +72,10 @@ public:
inline void swap(QSet<T> &other) noexcept { q_hash.swap(other.q_hash); }
template <typename U = T>
- QTypeTraits::compare_eq_result<U> operator==(const QSet<T> &other) const
+ QTypeTraits::compare_eq_result_container<QSet, U> operator==(const QSet<T> &other) const
{ return q_hash == other.q_hash; }
template <typename U = T>
- QTypeTraits::compare_eq_result<U> operator!=(const QSet<T> &other) const
+ QTypeTraits::compare_eq_result_container<QSet, U> operator!=(const QSet<T> &other) const
{ return q_hash != other.q_hash; }
inline qsizetype size() const { return q_hash.size(); }
diff --git a/tests/auto/corelib/tools/collections/tst_collections.cpp b/tests/auto/corelib/tools/collections/tst_collections.cpp
index 9dbaa9c386..0fa252427a 100644
--- a/tests/auto/corelib/tools/collections/tst_collections.cpp
+++ b/tests/auto/corelib/tools/collections/tst_collections.cpp
@@ -160,6 +160,150 @@ struct Pod {
int i1, i2;
};
+// Compile-time checks for recursive containers
+struct Dummy
+{
+ bool operator==(const Dummy &) const { return false; }
+ bool operator<(const Dummy &) const { return false; }
+};
+
+struct RecursiveList : public QList<RecursiveList> {};
+struct RecursiveSet : public QSet<RecursiveSet> {};
+struct RecursiveMapV : public QMap<Dummy, RecursiveMapV> {};
+struct RecursiveMapK : public QMap<RecursiveMapK, Dummy> {};
+struct RecursiveMultiMapV : public QMultiMap<Dummy, RecursiveMultiMapV> {};
+struct RecursiveMultiMapK : public QMultiMap<RecursiveMultiMapK, Dummy> {};
+struct RecursiveHashV : public QHash<Dummy, RecursiveHashV> {};
+struct RecursiveHashK : public QHash<RecursiveHashK, Dummy> {};
+struct RecursiveMultiHashV : public QMultiHash<Dummy, RecursiveMultiHashV> {};
+struct RecursiveMultiHashK : public QMultiHash<RecursiveMultiHashK, Dummy> {};
+
+struct Empty {};
+struct NoCmpParamRecursiveMapV : public QMap<Empty, NoCmpParamRecursiveMapV> {};
+struct NoCmpParamRecursiveMapK : public QMap<NoCmpParamRecursiveMapK, Empty> {};
+struct NoCmpParamRecursiveMultiMapV : public QMultiMap<Empty, NoCmpParamRecursiveMultiMapV> {};
+struct NoCmpParamRecursiveMultiMapK : public QMultiMap<NoCmpParamRecursiveMultiMapK, Empty> {};
+struct NoCmpParamRecursiveHashV : public QHash<Empty, NoCmpParamRecursiveHashV> {};
+struct NoCmpParamRecursiveHashK : public QHash<NoCmpParamRecursiveHashK, Empty> {};
+struct NoCmpParamRecursiveMultiHashV : public QMultiHash<Empty, NoCmpParamRecursiveMultiHashV> {};
+struct NoCmpParamRecursiveMultiHashK : public QMultiHash<NoCmpParamRecursiveMultiHashK, Empty> {};
+
+struct NoCmpRecursiveList : public QList<NoCmpRecursiveList>
+{
+ bool operator==(const RecursiveList &) const = delete;
+ bool operator<(const RecursiveList &) const = delete;
+};
+struct NoCmpRecursiveSet : public QSet<NoCmpRecursiveSet>
+{
+ bool operator==(const NoCmpRecursiveSet &) const = delete;
+};
+struct NoCmpRecursiveMapV : public QMap<Dummy, NoCmpRecursiveMapV>
+{
+ bool operator==(const NoCmpRecursiveMapV &) const = delete;
+};
+struct NoCmpRecursiveMapK : public QMap<NoCmpRecursiveMapK, Dummy>
+{
+ bool operator==(const NoCmpRecursiveMapK &) const = delete;
+};
+struct NoCmpRecursiveMultiMapV : public QMultiMap<Dummy, NoCmpRecursiveMultiMapV>
+{
+ bool operator==(const NoCmpRecursiveMultiMapV &) const = delete;
+};
+struct NoCmpRecursiveMultiMapK : public QMultiMap<NoCmpRecursiveMultiMapK, Dummy>
+{
+ bool operator==(const NoCmpRecursiveMultiMapK &) const = delete;
+};
+struct NoCmpRecursiveHashV : public QHash<Dummy, NoCmpRecursiveHashV>
+{
+ bool operator==(const NoCmpRecursiveHashV &) const = delete;
+};
+struct NoCmpRecursiveHashK : public QHash<NoCmpRecursiveHashK, Dummy>
+{
+ bool operator==(const NoCmpRecursiveHashK &) const = delete;
+};
+struct NoCmpRecursiveMultiHashV : public QMultiHash<Dummy, NoCmpRecursiveMultiHashV>
+{
+ bool operator==(const NoCmpRecursiveMultiHashV &) const = delete;
+};
+struct NoCmpRecursiveMultiHashK : public QMultiHash<NoCmpRecursiveMultiHashK, Dummy>
+{
+ bool operator==(const NoCmpRecursiveMultiHashK &) const = delete;
+};
+
+uint qHash(const Dummy &) { return 0; }
+uint qHash(const RecursiveSet &) { return 0; }
+uint qHash(const RecursiveHashK &) { return 0; }
+uint qHash(const RecursiveHashV &) { return 0; }
+uint qHash(const RecursiveMultiHashK &) { return 0; }
+uint qHash(const RecursiveMultiHashV &) { return 0; }
+
+Q_DECLARE_METATYPE(RecursiveList);
+Q_DECLARE_METATYPE(RecursiveSet);
+Q_DECLARE_METATYPE(RecursiveMapV);
+Q_DECLARE_METATYPE(RecursiveMapK);
+Q_DECLARE_METATYPE(RecursiveMultiMapV);
+Q_DECLARE_METATYPE(RecursiveMultiMapK);
+Q_DECLARE_METATYPE(RecursiveHashV);
+Q_DECLARE_METATYPE(RecursiveHashK);
+Q_DECLARE_METATYPE(RecursiveMultiHashV);
+Q_DECLARE_METATYPE(RecursiveMultiHashK);
+
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMapV);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMapK);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMultiMapV);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMultiMapK);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveHashK);
+// TODO: fix, this requires operator== from key type (QTBUG-96256)
+// Q_DECLARE_METATYPE(NoCmpParamRecursiveHashV);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMultiHashK);
+// TODO: fix, this requires operator== from key type (QTBUG-96256)
+// Q_DECLARE_METATYPE(NoCmpParamRecursiveMultiHashK);
+
+Q_DECLARE_METATYPE(NoCmpRecursiveList);
+// TODO: fix, this requires operator== (QTBUG-96257)
+// Q_DECLARE_METATYPE(NoCmpRecursiveSet);
+Q_DECLARE_METATYPE(NoCmpRecursiveMapV);
+Q_DECLARE_METATYPE(NoCmpRecursiveMapK);
+Q_DECLARE_METATYPE(NoCmpRecursiveMultiMapV);
+Q_DECLARE_METATYPE(NoCmpRecursiveMultiMapK);
+Q_DECLARE_METATYPE(NoCmpRecursiveHashV);
+Q_DECLARE_METATYPE(NoCmpRecursiveHashK);
+Q_DECLARE_METATYPE(NoCmpRecursiveMultiHashV);
+Q_DECLARE_METATYPE(NoCmpRecursiveMultiHashK);
+
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveList>);
+static_assert(QTypeTraits::has_operator_less_than_v<RecursiveList>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveSet>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMapV>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMapK>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMultiMapV>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMultiMapK>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveHashV>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveHashK>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMultiHashV>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMultiHashK>);
+
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMapV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMapK>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMultiMapV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMultiMapK>);
+static_assert(QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveHashV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveHashK>);
+static_assert(QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMultiHashV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMultiHashK>);
+
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveList>);
+static_assert(!QTypeTraits::has_operator_less_than_v<NoCmpRecursiveList>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveSet>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMapV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMapK>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMultiMapV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMultiMapK>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveHashV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveHashK>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMultiHashV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMultiHashK>);
+
void tst_Collections::typeinfo()
{
QVERIFY(QTypeInfo<int*>::isPointer);