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>
This commit is contained in:
parent
6c36fd8af7
commit
8ad9e81694
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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(";
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user