diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h index ec435867656..9a46d1296a7 100644 --- a/src/corelib/global/qtypeinfo.h +++ b/src/corelib/global/qtypeinfo.h @@ -334,17 +334,29 @@ struct has_operator_equal : detail::expand_operator_equal {}; template inline constexpr bool has_operator_equal_v = has_operator_equal::value; +template +using has_operator_equal_container = std::disjunction, QTypeTraits::has_operator_equal>; + template struct has_operator_less_than : detail::expand_operator_less_than {}; template inline constexpr bool has_operator_less_than_v = has_operator_less_than::value; +template +using has_operator_less_than_container = std::disjunction, QTypeTraits::has_operator_less_than>; + template using compare_eq_result = std::enable_if_t...>, bool>; +template +using compare_eq_result_container = std::enable_if_t...>, bool>; + template using compare_lt_result = std::enable_if_t...>, bool>; +template +using compare_lt_result_container = std::enable_if_t...>, bool>; + namespace detail { template @@ -362,6 +374,9 @@ struct has_ostream_operator inline constexpr bool has_ostream_operator_v = has_ostream_operator::value; +template +using has_ostream_operator_container = std::disjunction, QTypeTraits::has_ostream_operator>; + template struct has_istream_operator : std::false_type {}; template @@ -369,6 +384,8 @@ struct has_istream_operator inline constexpr bool has_istream_operator_v = has_istream_operator::value; +template +using has_istream_operator_container = std::disjunction, QTypeTraits::has_istream_operator>; template inline constexpr bool has_stream_operator_v = has_ostream_operator_v && has_istream_operator_v; diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 5e23c76cba9..e11431c673b 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -243,8 +243,12 @@ template using QDebugIfHasDebugStream = std::enable_if_t...>, QDebug>; +template +using QDebugIfHasDebugStreamContainer = + std::enable_if_t...>, QDebug>; + template -inline QDebugIfHasDebugStream operator<<(QDebug debug, const QList &vec) +inline QDebugIfHasDebugStreamContainer, T> operator<<(QDebug debug, const QList &vec) { return QtPrivate::printSequentialContainer(debug, "QList", vec); } @@ -274,25 +278,25 @@ inline QDebugIfHasDebugStream operator<<(QDebug debug, const std::multim } template -inline QDebugIfHasDebugStream operator<<(QDebug debug, const QMap &map) +inline QDebugIfHasDebugStreamContainer, Key, T> operator<<(QDebug debug, const QMap &map) { return QtPrivate::printAssociativeContainer(debug, "QMap", map); } template -inline QDebugIfHasDebugStream operator<<(QDebug debug, const QMultiMap &map) +inline QDebugIfHasDebugStreamContainer, Key, T> operator<<(QDebug debug, const QMultiMap &map) { return QtPrivate::printAssociativeContainer(debug, "QMultiMap", map); } template -inline QDebugIfHasDebugStream operator<<(QDebug debug, const QHash &hash) +inline QDebugIfHasDebugStreamContainer, Key, T> operator<<(QDebug debug, const QHash &hash) { return QtPrivate::printAssociativeContainer(debug, "QHash", hash); } template -inline QDebugIfHasDebugStream operator<<(QDebug debug, const QMultiHash &hash) +inline QDebugIfHasDebugStreamContainer, Key, T> operator<<(QDebug debug, const QMultiHash &hash) { return QtPrivate::printAssociativeContainer(debug, "QMultiHash", hash); } @@ -306,7 +310,7 @@ inline QDebugIfHasDebugStream operator<<(QDebug debug, const std::pair -inline QDebugIfHasDebugStream operator<<(QDebug debug, const QSet &set) +inline QDebugIfHasDebugStreamContainer, T> operator<<(QDebug debug, const QSet &set) { return QtPrivate::printSequentialContainer(debug, "QSet", set); } diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h index c1b521c8516..2d5a15304be 100644 --- a/src/corelib/serialization/qdatastream.h +++ b/src/corelib/serialization/qdatastream.h @@ -350,9 +350,16 @@ QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c) template using QDataStreamIfHasOStreamOperators = std::enable_if_t...>, QDataStream &>; +template +using QDataStreamIfHasOStreamOperatorsContainer = + std::enable_if_t...>, QDataStream &>; + template using QDataStreamIfHasIStreamOperators = std::enable_if_t...>, QDataStream &>; +template +using QDataStreamIfHasIStreamOperatorsContainer = + std::enable_if_t...>, QDataStream &>; /***************************************************************************** QDataStream inline functions @@ -424,74 +431,74 @@ operator>>(QDataStream &s, T &t) { return s >> reinterpret_cast::type &>(t); } template -inline QDataStreamIfHasIStreamOperators operator>>(QDataStream &s, QList &v) +inline QDataStreamIfHasIStreamOperatorsContainer, T> operator>>(QDataStream &s, QList &v) { return QtPrivate::readArrayBasedContainer(s, v); } template -inline QDataStreamIfHasOStreamOperators operator<<(QDataStream &s, const QList &v) +inline QDataStreamIfHasOStreamOperatorsContainer, T> operator<<(QDataStream &s, const QList &v) { return QtPrivate::writeSequentialContainer(s, v); } template -inline QDataStreamIfHasIStreamOperators operator>>(QDataStream &s, QSet &set) +inline QDataStreamIfHasIStreamOperatorsContainer, T> operator>>(QDataStream &s, QSet &set) { return QtPrivate::readListBasedContainer(s, set); } template -inline QDataStreamIfHasOStreamOperators operator<<(QDataStream &s, const QSet &set) +inline QDataStreamIfHasOStreamOperatorsContainer, T> operator<<(QDataStream &s, const QSet &set) { return QtPrivate::writeSequentialContainer(s, set); } template -inline QDataStreamIfHasIStreamOperators operator>>(QDataStream &s, QHash &hash) +inline QDataStreamIfHasIStreamOperatorsContainer, Key, T> operator>>(QDataStream &s, QHash &hash) { return QtPrivate::readAssociativeContainer(s, hash); } template -inline QDataStreamIfHasOStreamOperators operator<<(QDataStream &s, const QHash &hash) +inline QDataStreamIfHasOStreamOperatorsContainer, Key, T> operator<<(QDataStream &s, const QHash &hash) { return QtPrivate::writeAssociativeContainer(s, hash); } template -inline QDataStreamIfHasIStreamOperators operator>>(QDataStream &s, QMultiHash &hash) +inline QDataStreamIfHasIStreamOperatorsContainer, Key, T> operator>>(QDataStream &s, QMultiHash &hash) { return QtPrivate::readAssociativeContainer(s, hash); } template -inline QDataStreamIfHasOStreamOperators operator<<(QDataStream &s, const QMultiHash &hash) +inline QDataStreamIfHasOStreamOperatorsContainer, Key, T> operator<<(QDataStream &s, const QMultiHash &hash) { return QtPrivate::writeAssociativeMultiContainer(s, hash); } template -inline QDataStreamIfHasIStreamOperators operator>>(QDataStream &s, QMap &map) +inline QDataStreamIfHasIStreamOperatorsContainer, Key, T> operator>>(QDataStream &s, QMap &map) { return QtPrivate::readAssociativeContainer(s, map); } template -inline QDataStreamIfHasOStreamOperators operator<<(QDataStream &s, const QMap &map) +inline QDataStreamIfHasOStreamOperatorsContainer, Key, T> operator<<(QDataStream &s, const QMap &map) { return QtPrivate::writeAssociativeContainer(s, map); } template -inline QDataStreamIfHasIStreamOperators operator>>(QDataStream &s, QMultiMap &map) +inline QDataStreamIfHasIStreamOperatorsContainer, Key, T> operator>>(QDataStream &s, QMultiMap &map) { return QtPrivate::readAssociativeContainer(s, map); } template -inline QDataStreamIfHasOStreamOperators operator<<(QDataStream &s, const QMultiMap &map) +inline QDataStreamIfHasOStreamOperatorsContainer, Key, T> operator<<(QDataStream &s, const QMultiMap &map) { return QtPrivate::writeAssociativeMultiContainer(s, map); } diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 25c00ce26fc..669a031fe89 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 - QTypeTraits::compare_eq_result operator==(const QHash &other) const noexcept + QTypeTraits::compare_eq_result_container operator==(const QHash &other) const noexcept { if (d == other.d) return true; @@ -836,7 +836,7 @@ public: return true; } template - QTypeTraits::compare_eq_result operator!=(const QHash &other) const noexcept + QTypeTraits::compare_eq_result_container 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 2811688e4b6..91aa7840cbb 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -277,7 +277,7 @@ public: void swap(QList &other) noexcept { qSwap(d, other.d); } template - QTypeTraits::compare_eq_result operator==(const QList &other) const + QTypeTraits::compare_eq_result_container operator==(const QList &other) const { if (size() != other.size()) return false; @@ -288,13 +288,13 @@ public: return d->compare(begin(), other.begin(), size()); } template - QTypeTraits::compare_eq_result operator!=(const QList &other) const + QTypeTraits::compare_eq_result_container operator!=(const QList &other) const { return !(*this == other); } template - QTypeTraits::compare_lt_result operator<(const QList &other) const + QTypeTraits::compare_lt_result_container operator<(const QList &other) const noexcept(noexcept(std::lexicographical_compare::const_iterator, typename QList::const_iterator>( std::declval>().begin(), std::declval>().end(), @@ -305,21 +305,21 @@ public: } template - QTypeTraits::compare_lt_result operator>(const QList &other) const + QTypeTraits::compare_lt_result_container operator>(const QList &other) const noexcept(noexcept(other < std::declval>())) { return other < *this; } template - QTypeTraits::compare_lt_result operator<=(const QList &other) const + QTypeTraits::compare_lt_result_container operator<=(const QList &other) const noexcept(noexcept(other < std::declval>())) { return !(other < *this); } template - QTypeTraits::compare_lt_result operator>=(const QList &other) const + QTypeTraits::compare_lt_result_container operator>=(const QList &other) const noexcept(noexcept(std::declval>() < other)) { return !(*this < other); diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index f71e95dd82f..f83fbe9c89e 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -277,7 +277,7 @@ public: } template friend - QTypeTraits::compare_eq_result operator==(const QMap &lhs, const QMap &rhs) + QTypeTraits::compare_eq_result_container operator==(const QMap &lhs, const QMap &rhs) { if (lhs.d == rhs.d) return true; @@ -288,7 +288,7 @@ public: } template friend - QTypeTraits::compare_eq_result operator!=(const QMap &lhs, const QMap &rhs) + QTypeTraits::compare_eq_result_container operator!=(const QMap &lhs, const QMap &rhs) { return !(lhs == rhs); } @@ -857,7 +857,7 @@ public: } template friend - QTypeTraits::compare_eq_result operator==(const QMultiMap &lhs, const QMultiMap &rhs) + QTypeTraits::compare_eq_result_container operator==(const QMultiMap &lhs, const QMultiMap &rhs) { if (lhs.d == rhs.d) return true; @@ -868,7 +868,7 @@ public: } template friend - QTypeTraits::compare_eq_result operator!=(const QMultiMap &lhs, const QMultiMap &rhs) + QTypeTraits::compare_eq_result_container 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 681ce9cbe24..565b8b56916 100644 --- a/src/corelib/tools/qset.h +++ b/src/corelib/tools/qset.h @@ -72,10 +72,10 @@ public: inline void swap(QSet &other) noexcept { q_hash.swap(other.q_hash); } template - QTypeTraits::compare_eq_result operator==(const QSet &other) const + QTypeTraits::compare_eq_result_container operator==(const QSet &other) const { return q_hash == other.q_hash; } template - QTypeTraits::compare_eq_result operator!=(const QSet &other) const + QTypeTraits::compare_eq_result_container operator!=(const QSet &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 34a352c614b..327b530c774 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 {}; +struct RecursiveSet : public QSet {}; +struct RecursiveMapV : public QMap {}; +struct RecursiveMapK : public QMap {}; +struct RecursiveMultiMapV : public QMultiMap {}; +struct RecursiveMultiMapK : public QMultiMap {}; +struct RecursiveHashV : public QHash {}; +struct RecursiveHashK : public QHash {}; +struct RecursiveMultiHashV : public QMultiHash {}; +struct RecursiveMultiHashK : public QMultiHash {}; + +struct Empty {}; +struct NoCmpParamRecursiveMapV : public QMap {}; +struct NoCmpParamRecursiveMapK : public QMap {}; +struct NoCmpParamRecursiveMultiMapV : public QMultiMap {}; +struct NoCmpParamRecursiveMultiMapK : public QMultiMap {}; +struct NoCmpParamRecursiveHashV : public QHash {}; +struct NoCmpParamRecursiveHashK : public QHash {}; +struct NoCmpParamRecursiveMultiHashV : public QMultiHash {}; +struct NoCmpParamRecursiveMultiHashK : public QMultiHash {}; + +struct NoCmpRecursiveList : public QList +{ + bool operator==(const RecursiveList &) const = delete; + bool operator<(const RecursiveList &) const = delete; +}; +struct NoCmpRecursiveSet : public QSet +{ + bool operator==(const NoCmpRecursiveSet &) const = delete; +}; +struct NoCmpRecursiveMapV : public QMap +{ + bool operator==(const NoCmpRecursiveMapV &) const = delete; +}; +struct NoCmpRecursiveMapK : public QMap +{ + bool operator==(const NoCmpRecursiveMapK &) const = delete; +}; +struct NoCmpRecursiveMultiMapV : public QMultiMap +{ + bool operator==(const NoCmpRecursiveMultiMapV &) const = delete; +}; +struct NoCmpRecursiveMultiMapK : public QMultiMap +{ + bool operator==(const NoCmpRecursiveMultiMapK &) const = delete; +}; +struct NoCmpRecursiveHashV : public QHash +{ + bool operator==(const NoCmpRecursiveHashV &) const = delete; +}; +struct NoCmpRecursiveHashK : public QHash +{ + bool operator==(const NoCmpRecursiveHashK &) const = delete; +}; +struct NoCmpRecursiveMultiHashV : public QMultiHash +{ + bool operator==(const NoCmpRecursiveMultiHashV &) const = delete; +}; +struct NoCmpRecursiveMultiHashK : public QMultiHash +{ + 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); +static_assert(QTypeTraits::has_operator_less_than_v); +static_assert(QTypeTraits::has_operator_equal_v); +static_assert(QTypeTraits::has_operator_equal_v); +static_assert(QTypeTraits::has_operator_equal_v); +static_assert(QTypeTraits::has_operator_equal_v); +static_assert(QTypeTraits::has_operator_equal_v); +static_assert(QTypeTraits::has_operator_equal_v); +static_assert(QTypeTraits::has_operator_equal_v); +static_assert(QTypeTraits::has_operator_equal_v); +static_assert(QTypeTraits::has_operator_equal_v); + +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); + +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_less_than_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); +static_assert(!QTypeTraits::has_operator_equal_v); + void tst_Collections::typeinfo() { QVERIFY(QTypeInfo::isPointer);