Constrain the data stream operators for containers
Check that we can successfully instantiate the data 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: Ib100a5242470d7fc8067058cc4d81af2fa9354b0 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
8ad9e81694
commit
3ef8ec2ee1
@ -464,6 +464,17 @@ struct has_ostream_operator<Stream, T, std::void_t<decltype(detail::reference<St
|
|||||||
template <typename Stream, typename T>
|
template <typename Stream, typename T>
|
||||||
constexpr bool has_ostream_operator_v = has_ostream_operator<Stream, T>::value;
|
constexpr bool has_ostream_operator_v = has_ostream_operator<Stream, T>::value;
|
||||||
|
|
||||||
|
template <typename Stream, typename, typename = void>
|
||||||
|
struct has_istream_operator : std::false_type {};
|
||||||
|
template <typename Stream, typename T>
|
||||||
|
struct has_istream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() >> detail::reference<T>())>>
|
||||||
|
: std::true_type {};
|
||||||
|
template <typename Stream, typename T>
|
||||||
|
constexpr bool has_istream_operator_v = has_istream_operator<Stream, T>::value;
|
||||||
|
|
||||||
|
template <typename Stream, typename T>
|
||||||
|
constexpr bool has_stream_operator_v = has_ostream_operator_v<Stream, T> && has_istream_operator_v<Stream, T>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -347,6 +347,13 @@ QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c)
|
|||||||
|
|
||||||
} // QtPrivate namespace
|
} // QtPrivate namespace
|
||||||
|
|
||||||
|
template<typename ...T>
|
||||||
|
using QDataStreamIfHasOStreamOperators =
|
||||||
|
std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator<QDataStream, T>...>, QDataStream &>;
|
||||||
|
template<typename ...T>
|
||||||
|
using QDataStreamIfHasIStreamOperators =
|
||||||
|
std::enable_if_t<std::conjunction_v<QTypeTraits::has_istream_operator<QDataStream, T>...>, QDataStream &>;
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
QDataStream inline functions
|
QDataStream inline functions
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
@ -406,88 +413,88 @@ operator>>(QDataStream &s, T &t)
|
|||||||
{ return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t); }
|
{ return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t); }
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline QDataStream &operator>>(QDataStream &s, QList<T> &v)
|
inline QDataStreamIfHasIStreamOperators<T> operator>>(QDataStream &s, QList<T> &v)
|
||||||
{
|
{
|
||||||
return QtPrivate::readArrayBasedContainer(s, v);
|
return QtPrivate::readArrayBasedContainer(s, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline QDataStream &operator<<(QDataStream &s, const QList<T> &v)
|
inline QDataStreamIfHasOStreamOperators<T> operator<<(QDataStream &s, const QList<T> &v)
|
||||||
{
|
{
|
||||||
return QtPrivate::writeSequentialContainer(s, v);
|
return QtPrivate::writeSequentialContainer(s, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline QDataStream &operator>>(QDataStream &s, QSet<T> &set)
|
inline QDataStreamIfHasIStreamOperators<T> operator>>(QDataStream &s, QSet<T> &set)
|
||||||
{
|
{
|
||||||
return QtPrivate::readListBasedContainer(s, set);
|
return QtPrivate::readListBasedContainer(s, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline QDataStream &operator<<(QDataStream &s, const QSet<T> &set)
|
inline QDataStreamIfHasOStreamOperators<T> operator<<(QDataStream &s, const QSet<T> &set)
|
||||||
{
|
{
|
||||||
return QtPrivate::writeSequentialContainer(s, set);
|
return QtPrivate::writeSequentialContainer(s, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Key, class T>
|
template <class Key, class T>
|
||||||
inline QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash)
|
inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QHash<Key, T> &hash)
|
||||||
{
|
{
|
||||||
return QtPrivate::readAssociativeContainer(s, hash);
|
return QtPrivate::readAssociativeContainer(s, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Key, class T>
|
template <class Key, class T>
|
||||||
|
|
||||||
inline QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash)
|
inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QHash<Key, T> &hash)
|
||||||
{
|
{
|
||||||
return QtPrivate::writeAssociativeContainer(s, hash);
|
return QtPrivate::writeAssociativeContainer(s, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Key, class T>
|
template <class Key, class T>
|
||||||
inline QDataStream &operator>>(QDataStream &s, QMultiHash<Key, T> &hash)
|
inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QMultiHash<Key, T> &hash)
|
||||||
{
|
{
|
||||||
return QtPrivate::readAssociativeContainer(s, hash);
|
return QtPrivate::readAssociativeContainer(s, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Key, class T>
|
template <class Key, class T>
|
||||||
inline QDataStream &operator<<(QDataStream &s, const QMultiHash<Key, T> &hash)
|
inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QMultiHash<Key, T> &hash)
|
||||||
{
|
{
|
||||||
return QtPrivate::writeAssociativeMultiContainer(s, hash);
|
return QtPrivate::writeAssociativeMultiContainer(s, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Key, class T>
|
template <class Key, class T>
|
||||||
inline QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map)
|
inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QMap<Key, T> &map)
|
||||||
{
|
{
|
||||||
return QtPrivate::readAssociativeContainer(s, map);
|
return QtPrivate::readAssociativeContainer(s, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Key, class T>
|
template <class Key, class T>
|
||||||
inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map)
|
inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QMap<Key, T> &map)
|
||||||
{
|
{
|
||||||
return QtPrivate::writeAssociativeContainer(s, map);
|
return QtPrivate::writeAssociativeContainer(s, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Key, class T>
|
template <class Key, class T>
|
||||||
inline QDataStream &operator>>(QDataStream &s, QMultiMap<Key, T> &map)
|
inline QDataStreamIfHasIStreamOperators<Key, T> operator>>(QDataStream &s, QMultiMap<Key, T> &map)
|
||||||
{
|
{
|
||||||
return QtPrivate::readAssociativeContainer(s, map);
|
return QtPrivate::readAssociativeContainer(s, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Key, class T>
|
template <class Key, class T>
|
||||||
inline QDataStream &operator<<(QDataStream &s, const QMultiMap<Key, T> &map)
|
inline QDataStreamIfHasOStreamOperators<Key, T> operator<<(QDataStream &s, const QMultiMap<Key, T> &map)
|
||||||
{
|
{
|
||||||
return QtPrivate::writeAssociativeMultiContainer(s, map);
|
return QtPrivate::writeAssociativeMultiContainer(s, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_DATASTREAM
|
#ifndef QT_NO_DATASTREAM
|
||||||
template <class T1, class T2>
|
template <class T1, class T2>
|
||||||
inline QDataStream& operator>>(QDataStream& s, std::pair<T1, T2> &p)
|
inline QDataStreamIfHasIStreamOperators<T1, T2> operator>>(QDataStream& s, std::pair<T1, T2> &p)
|
||||||
{
|
{
|
||||||
s >> p.first >> p.second;
|
s >> p.first >> p.second;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T1, class T2>
|
template <class T1, class T2>
|
||||||
inline QDataStream& operator<<(QDataStream& s, const std::pair<T1, T2> &p)
|
inline QDataStreamIfHasOStreamOperators<T1, T2> operator<<(QDataStream& s, const std::pair<T1, T2> &p)
|
||||||
{
|
{
|
||||||
s << p.first << p.second;
|
s << p.first << p.second;
|
||||||
return s;
|
return s;
|
||||||
|
@ -35,11 +35,13 @@
|
|||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <QFutureSynchronizer>
|
#include <QFutureSynchronizer>
|
||||||
|
|
||||||
static_assert(QTypeTraits::has_ostream_v<QDebug, int>);
|
static_assert(QTypeTraits::has_ostream_operator_v<QDebug, int>);
|
||||||
static_assert(QTypeTraits::has_ostream_v<QDebug, QList<int>>);
|
static_assert(QTypeTraits::has_ostream_operator_v<QDebug, QList<int>>);
|
||||||
|
static_assert(QTypeTraits::has_ostream_operator_v<QDebug, QMap<int, QString>>);
|
||||||
struct NonStreamable {};
|
struct NonStreamable {};
|
||||||
static_assert(!QTypeTraits::has_ostream_v<QDebug, NonStreamable>);
|
static_assert(!QTypeTraits::has_ostream_operator_v<QDebug, NonStreamable>);
|
||||||
static_assert(!QTypeTraits::has_ostream_v<QDebug, QList<NonStreamable>>);
|
static_assert(!QTypeTraits::has_ostream_operator_v<QDebug, QList<NonStreamable>>);
|
||||||
|
static_assert(!QTypeTraits::has_ostream_operator_v<QDebug, QMap<int, NonStreamable>>);
|
||||||
|
|
||||||
class tst_QDebug: public QObject
|
class tst_QDebug: public QObject
|
||||||
{
|
{
|
||||||
|
@ -36,6 +36,14 @@
|
|||||||
#include <QtGui/QPixmap>
|
#include <QtGui/QPixmap>
|
||||||
#include <QtGui/QTextLength>
|
#include <QtGui/QTextLength>
|
||||||
|
|
||||||
|
static_assert(QTypeTraits::has_ostream_operator_v<QDataStream, int>);
|
||||||
|
static_assert(QTypeTraits::has_ostream_operator_v<QDataStream, QList<int>>);
|
||||||
|
static_assert(QTypeTraits::has_ostream_operator_v<QDataStream, QMap<int, QString>>);
|
||||||
|
struct NonStreamable {};
|
||||||
|
static_assert(!QTypeTraits::has_ostream_operator_v<QDataStream, NonStreamable>);
|
||||||
|
static_assert(!QTypeTraits::has_ostream_operator_v<QDataStream, QList<NonStreamable>>);
|
||||||
|
static_assert(!QTypeTraits::has_ostream_operator_v<QDataStream, QMap<int, NonStreamable>>);
|
||||||
|
|
||||||
class tst_QDataStream : public QObject
|
class tst_QDataStream : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Loading…
x
Reference in New Issue
Block a user