summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2020-07-06 13:08:40 +0200
committerLars Knoll <lars.knoll@qt.io>2020-08-15 14:43:23 +0200
commit8ad9e81694fda39fbecebb9f97491004e9ac8c41 (patch)
treeb5a5e9bc6bd95dea730cb466627e8a225bd1ab94 /src/corelib
parent6c36fd8af7e873defa3843f49848a14980561647 (diff)
Constrain the debug stream operators for containers
Check that we can successfully instantiate the debug stream operator for a container before we actually try. This is required so we can automate registration of debug stream operators with QMetaType. Change-Id: I3943e7a443751d250c33b2ca1b9cf29207cfe6c4 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/global/qtypeinfo.h19
-rw-r--r--src/corelib/io/qdebug.h28
2 files changed, 35 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(";