diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index d4cc46dbe42..970fe15a776 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -1188,6 +1188,15 @@ QDebug &QDebug::putTupleLikeImplImpl(const char *ns, const char *what, \c T need to support streaming into QDebug. */ +/*! + \fn template QDebug operator<<(QDebug debug, const std::unordered_map &unordered_map) + \relates QDebug + \since 6.9 + + Writes the contents of \a map to \a debug. Both \c Key and + \c T need to support streaming into QDebug. +*/ + /*! \fn template QDebug operator<<(QDebug debug, const QHash &hash) \relates QDebug diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 41ada051d72..3fc63552953 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 1 @@ -436,6 +437,12 @@ inline QDebugIfHasDebugStream operator<<(QDebug debug, const std::multim return QtPrivate::printSequentialContainer(std::move(debug), "std::multimap", map); // yes, sequential: *it is std::pair } +template +inline QDebug operator<<(QDebug debug, const std::unordered_map &unordered_map) +{ + return QtPrivate::printSequentialContainer(std::move(debug), "std::unordered_map", unordered_map); // yes, sequential: *it is std::pair +} + template inline QDebugIfHasDebugStreamContainer, Key, T> operator<<(QDebug debug, const QMap &map) { diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp index 6c6ab7aa87b..3d1617fff21 100644 --- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp +++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp @@ -26,6 +26,7 @@ namespace pmr = std::pmr; namespace pmr = std; #endif #include +#include using namespace std::chrono; using namespace q20::chrono; @@ -36,6 +37,7 @@ static_assert(QTypeTraits::has_ostream_operator_v); static_assert(QTypeTraits::has_ostream_operator_v>); static_assert(QTypeTraits::has_ostream_operator_v>); static_assert(QTypeTraits::has_ostream_operator_v>>); +static_assert(QTypeTraits::has_ostream_operator_v>); struct NonStreamable {}; static_assert(!QTypeTraits::has_ostream_operator_v); static_assert(!QTypeTraits::has_ostream_operator_v>); @@ -84,6 +86,7 @@ private slots: void qDebugQLatin1String() const; void qDebugStdPair() const; void qDebugStdTuple() const; + void qDebugStdUnorderedMap() const; void qDebugStdString() const; void qDebugStdStringView() const; void qDebugStdWString() const; @@ -770,6 +773,46 @@ void tst_QDebug::qDebugStdTuple() const } } +void tst_QDebug::qDebugStdUnorderedMap() const +{ + QByteArray file, function; + int line = 0; + MessageHandlerSetter mhs(myMessageHandler); + + { + QDebug d = qDebug(); + std::unordered_map unorderedMap{{1, "One"}, {2, "Two"}, {3, "Three"}}; + d.nospace().noquote() << unorderedMap; + } +#ifndef QT_NO_MESSAGELOGCONTEXT + file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO; +#endif + QCOMPARE(s_msgType, QtDebugMsg); + + QStringList expectedValues = {"std::unordered_map","std::pair(1, One)","std::pair(2, Two)","std::pair(3, Three)"}; + for (const QString &expextedValue : expectedValues) { + QVERIFY(s_msg.contains(expextedValue)); + } + QCOMPARE(s_file, file); + QCOMPARE(s_line, line); + QCOMPARE(s_function, function); + + { + qDebug() << std::unordered_map{{"quarter", 0.25f}, {"half", 0.5f}}; + } + + expectedValues= {"std::unordered_map","std::pair(\"quarter\", 0.25)","std::pair(\"half\", 0.5)"}; + for (const QString &expextedValue : expectedValues) { + QVERIFY(s_msg.contains(expextedValue)); + } + + { + qDebug()<< std::unordered_map {}; + } + + QCOMPARE(s_msg, "std::unordered_map()"_L1); +} + void tst_QDebug::qDebugStdString() const { QString file, function;