summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qtypeinfo.h19
-rw-r--r--src/corelib/io/qdebug.h28
-rw-r--r--tests/auto/corelib/io/qdebug/tst_qdebug.cpp6
3 files changed, 41 insertions, 12 deletions
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h
index be21526339..2f7bb414b5 100644
--- a/src/corelib/global/qtypeinfo.h
+++ b/src/corelib/global/qtypeinfo.h
@@ -48,6 +48,8 @@
QT_BEGIN_NAMESPACE
+class QDebug;
+
/*
QTypeInfo - type trait functionality
*/
@@ -445,6 +447,23 @@ using compare_eq_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_o
template <typename ...T>
using compare_lt_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than<T>...>, bool>;
+namespace detail {
+
+template<typename T>
+const T const_value();
+template<typename T>
+T &reference();
+
+}
+
+template <typename Stream, typename, typename = void>
+struct has_ostream_operator : std::false_type {};
+template <typename Stream, typename T>
+struct has_ostream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() << detail::const_value<T>())>>
+ : std::true_type {};
+template <typename Stream, typename T>
+constexpr bool has_ostream_operator_v = has_ostream_operator<Stream, T>::value;
+
}
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index 77004ef952..d858eb933b 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -262,62 +262,66 @@ inline QDebug printAssociativeContainer(QDebug debug, const char *which, const A
} // namespace QtPrivate
+template<typename ...T>
+using QDebugIfHasDebugStream =
+ std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator<QDebug, T>...>, QDebug>;
+
template<typename T>
-inline QDebug operator<<(QDebug debug, const QList<T> &vec)
+inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QList<T> &vec)
{
return QtPrivate::printSequentialContainer(debug, "QList", vec);
}
template <typename T, typename Alloc>
-inline QDebug operator<<(QDebug debug, const std::vector<T, Alloc> &vec)
+inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::vector<T, Alloc> &vec)
{
return QtPrivate::printSequentialContainer(debug, "std::vector", vec);
}
template <typename T, typename Alloc>
-inline QDebug operator<<(QDebug debug, const std::list<T, Alloc> &vec)
+inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::list<T, Alloc> &vec)
{
return QtPrivate::printSequentialContainer(debug, "std::list", vec);
}
template <typename Key, typename T, typename Compare, typename Alloc>
-inline QDebug operator<<(QDebug debug, const std::map<Key, T, Compare, Alloc> &map)
+inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::map<Key, T, Compare, Alloc> &map)
{
return QtPrivate::printSequentialContainer(debug, "std::map", map); // yes, sequential: *it is std::pair
}
template <typename Key, typename T, typename Compare, typename Alloc>
-inline QDebug operator<<(QDebug debug, const std::multimap<Key, T, Compare, Alloc> &map)
+inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::multimap<Key, T, Compare, Alloc> &map)
{
return QtPrivate::printSequentialContainer(debug, "std::multimap", map); // yes, sequential: *it is std::pair
}
template <class Key, class T>
-inline QDebug operator<<(QDebug debug, const QMap<Key, T> &map)
+inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const QMap<Key, T> &map)
{
return QtPrivate::printAssociativeContainer(debug, "QMap", map);
}
template <class Key, class T>
-inline QDebug operator<<(QDebug debug, const QMultiMap<Key, T> &map)
+inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const QMultiMap<Key, T> &map)
{
return QtPrivate::printAssociativeContainer(debug, "QMultiMap", map);
}
template <class Key, class T>
-inline QDebug operator<<(QDebug debug, const QHash<Key, T> &hash)
+inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const QHash<Key, T> &hash)
{
return QtPrivate::printAssociativeContainer(debug, "QHash", hash);
}
template <class Key, class T>
-inline QDebug operator<<(QDebug debug, const QMultiHash<Key, T> &hash)
+inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const QMultiHash<Key, T> &hash)
{
return QtPrivate::printAssociativeContainer(debug, "QMultiHash", hash);
}
template <class T1, class T2>
-inline QDebug operator<<(QDebug debug, const std::pair<T1, T2> &pair)
+inline QDebugIfHasDebugStream<T1, T2> operator<<(QDebug debug, const std::pair<T1, T2> &pair)
{
const QDebugStateSaver saver(debug);
debug.nospace() << "std::pair(" << pair.first << ',' << pair.second << ')';
@@ -325,13 +329,13 @@ inline QDebug operator<<(QDebug debug, const std::pair<T1, T2> &pair)
}
template <typename T>
-inline QDebug operator<<(QDebug debug, const QSet<T> &set)
+inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QSet<T> &set)
{
return QtPrivate::printSequentialContainer(debug, "QSet", set);
}
template <class T>
-inline QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache)
+inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QContiguousCache<T> &cache)
{
const QDebugStateSaver saver(debug);
debug.nospace() << "QContiguousCache(";
diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
index ece9be642a..72412aa44d 100644
--- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
+++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
@@ -35,6 +35,12 @@
#include <QtConcurrentRun>
#include <QFutureSynchronizer>
+static_assert(QTypeTraits::has_ostream_v<QDebug, int>);
+static_assert(QTypeTraits::has_ostream_v<QDebug, QList<int>>);
+struct NonStreamable {};
+static_assert(!QTypeTraits::has_ostream_v<QDebug, NonStreamable>);
+static_assert(!QTypeTraits::has_ostream_v<QDebug, QList<NonStreamable>>);
+
class tst_QDebug: public QObject
{
Q_OBJECT