QDebug: make std::optional stream operator SCARY

Piggy-back on the recently-added, type-erased, std::tuple stream
operator to handle std::optional the same way.

While std::optional doesn't support the Tuple Protocol, and we
therefore can't use putTuple() directly, we can still use
putTupleImplImpl() if we set up its arguments manually.

[ChangeLog][Potentially Source-Incompatible Changes][QDebug] The
std::optional streaming operator is now a member of QDebug, not a free
function. This breaks users that rely on the exact definition of the
operator (e.g. `operator<<(d, opt)`). A backwards-compatible fix is to
call the operator with infix notation (d << opt) only, and to avoid
const QDebug objects.

Pick-to: 6.9
Change-Id: Ib040d65953ca9d3892aee5bdb597d6d30a9694b1
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
This commit is contained in:
Marc Mutz 2024-10-21 15:01:13 +02:00
parent ec011141b8
commit 08320bfe2b
2 changed files with 12 additions and 13 deletions

View File

@ -1258,10 +1258,9 @@ QDebug &QDebug::putTupleLikeImplImpl(const char *ns, const char *what,
/*!
\since 6.7
\fn template <class T> QDebug operator<<(QDebug debug, const std::optional<T> &opt)
\relates QDebug
\fn template <class T, QDebug::if_streamable<T>> QDebug::operator<<(const std::optional<T> &opt)
Writes the contents of \a opt (or \c nullopt if not set) to \a debug.
Writes the contents of \a opt (or \c nullopt if not set) to this stream.
\c T needs to support streaming into QDebug.
*/

View File

@ -299,6 +299,16 @@ public:
return putTupleLike("std", "tuple", t);
}
template <typename T, if_streamable<T> = true>
QDebug &operator<<(const std::optional<T> &o)
{
if (!o)
return *this << std::nullopt;
StreamTypeErased s = &streamTypeErased<std::remove_cv_t<T>>;
const void *d = std::addressof(*o);
return putTupleLikeImplImpl("std", "optional", 1, &s, &d);
}
private:
template <typename T>
using if_ordering_type = std::enable_if_t<QtOrderingPrivate::is_ordering_type_v<T>, bool>;
@ -490,16 +500,6 @@ inline QDebugIfHasDebugStreamContainer<QMultiHash<Key, T>, Key, T> operator<<(QD
return QtPrivate::printAssociativeContainer(std::move(debug), "QMultiHash", hash);
}
template <class T>
inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::optional<T> &opt)
{
if (!opt)
return debug << std::nullopt;
const QDebugStateSaver saver(debug);
debug.nospace() << "std::optional(" << *opt << ')';
return debug;
}
template <class T1, class T2>
inline QDebugIfHasDebugStream<T1, T2> operator<<(QDebug debug, const std::pair<T1, T2> &pair)
{