diff options
-rw-r--r-- | src/corelib/global/qtypeinfo.h | 19 | ||||
-rw-r--r-- | src/corelib/io/qdebug.h | 28 | ||||
-rw-r--r-- | tests/auto/corelib/io/qdebug/tst_qdebug.cpp | 6 |
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 |