QDebug: fix std::string/view stream operators; add u8 versions
Make them templates, for two reasons: - so they can accept std::pmr types and, in general, any basic_string with custom allocators and char_traits - to break overload ambiguities with the Qt string view types Also, add the missing C++20 char8_t overloads. Also, avoid creation of a QString in the sizeof(wchar_t) == 2 case (Windows). Add a comment to optimize for the sizeof(wchar_t) != 2 case later. Found in API review. Pick-to: 6.5 Change-Id: I30139520f582a38863a0936f8eca4b1ed33e37c8 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
a84b2e5973
commit
52c7f699ac
@ -765,75 +765,20 @@ QDebug &QDebug::resetFormat()
|
||||
|
||||
/*!
|
||||
\since 6.5
|
||||
\fn QDebug &QDebug::operator<<(const std::string &s)
|
||||
\fn template <typename Char, typename...Args> QDebug &QDebug::operator<<(const std::basic_string<Char, Args...> &s)
|
||||
\fn template <typename Char, typename...Args> QDebug &QDebug::operator<<(std::basic_string_view<Char, Args...> s)
|
||||
|
||||
Converts \a s to a QUtf8StringView,
|
||||
writes the result to the stream and returns
|
||||
a reference to the stream.
|
||||
*/
|
||||
Writes the string or string-view \a s to the stream and returns a reference
|
||||
to the stream.
|
||||
|
||||
/*!
|
||||
\since 6.5
|
||||
\fn QDebug &QDebug::operator<<(std::string_view s)
|
||||
|
||||
Converts \a s to a QUtf8StringView,
|
||||
writes the result to the stream and returns
|
||||
a reference to the stream.
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\since 6.5
|
||||
\fn QDebug &QDebug::operator<<(const std::wstring &s)
|
||||
|
||||
Converts \a s to a QString via QString::fromStdWString(),
|
||||
writes the result to the stream and returns
|
||||
a reference to the stream.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 6.5
|
||||
\fn QDebug &QDebug::operator<<(std::wstring_view s)
|
||||
|
||||
Converts \a s to a QString via QString::fromWCharArray(),
|
||||
writes the result to the stream and returns
|
||||
a reference to the stream.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 6.5
|
||||
\fn QDebug &QDebug::operator<<(const std::u16string &s)
|
||||
|
||||
Converts \a s to a QStringView,
|
||||
writes the result to the stream and returns
|
||||
a reference to the stream.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 6.5
|
||||
\fn QDebug &QDebug::operator<<(std::u16string_view s)
|
||||
|
||||
Converts \a s to a QStringView,
|
||||
writes the result to the stream and returns
|
||||
a reference to the stream.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 6.5
|
||||
\fn QDebug &QDebug::operator<<(const std::u32string &s)
|
||||
|
||||
Converts \a s to a QString via QString::fromUcs4(),
|
||||
writes the result to the stream and returns
|
||||
a reference to the stream.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 6.5
|
||||
\fn QDebug &QDebug::operator<<(std::u32string_view s)
|
||||
|
||||
Converts \a s to a QString via QString::fromUcs4(),
|
||||
writes the result to the stream and returns
|
||||
a reference to the stream.
|
||||
These operators only participate in overload resolution if \c Char is one of
|
||||
\list
|
||||
\li char
|
||||
\li char8_t (C++20 only)
|
||||
\li char16_t
|
||||
\li char32_t
|
||||
\li wchar_t
|
||||
\endlist
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
@ -129,29 +129,65 @@ public:
|
||||
inline QDebug &operator<<(QTextStreamManipulator m)
|
||||
{ stream->ts << m; return *this; }
|
||||
|
||||
inline QDebug &operator<<(const std::string &s)
|
||||
#ifdef Q_QDOC
|
||||
template <typename Char, typename...Args>
|
||||
QDebug &operator<<(const std::basic_string<Char, Args...> &s);
|
||||
|
||||
template <typename Char, typename...Args>
|
||||
QDebug &operator<<(std::basic_string_view<Char, Args...> s);
|
||||
#else
|
||||
template <typename...Args>
|
||||
QDebug &operator<<(const std::basic_string<char, Args...> &s)
|
||||
{ return *this << QUtf8StringView(s); }
|
||||
|
||||
inline QDebug &operator<<(std::string_view s)
|
||||
template <typename...Args>
|
||||
QDebug &operator<<(std::basic_string_view<char, Args...> s)
|
||||
{ return *this << QUtf8StringView(s); }
|
||||
|
||||
inline QDebug &operator<<(const std::wstring &s)
|
||||
{ return *this << QString::fromStdWString(s); }
|
||||
#ifdef __cpp_char8_t
|
||||
template <typename...Args>
|
||||
QDebug &operator<<(const std::basic_string<char8_t, Args...> &s)
|
||||
{ return *this << QUtf8StringView(s); }
|
||||
|
||||
inline QDebug &operator<<(std::wstring_view s)
|
||||
{ return *this << QString::fromWCharArray(s.data(), s.size()); }
|
||||
template <typename...Args>
|
||||
QDebug &operator<<(std::basic_string_view<char8_t, Args...> s)
|
||||
{ return *this << QUtf8StringView(s); }
|
||||
#endif // __cpp_char8_t
|
||||
|
||||
inline QDebug &operator<<(const std::u16string &s)
|
||||
template <typename...Args>
|
||||
QDebug &operator<<(const std::basic_string<char16_t, Args...> &s)
|
||||
{ return *this << QStringView(s); }
|
||||
|
||||
inline QDebug &operator<<(std::u16string_view s)
|
||||
template <typename...Args>
|
||||
QDebug &operator<<(std::basic_string_view<char16_t, Args...> s)
|
||||
{ return *this << QStringView(s); }
|
||||
|
||||
inline QDebug &operator<<(const std::u32string &s)
|
||||
template <typename...Args>
|
||||
QDebug &operator<<(const std::basic_string<wchar_t, Args...> &s)
|
||||
{
|
||||
if constexpr (sizeof(wchar_t) == 2)
|
||||
return *this << QStringView(s);
|
||||
else
|
||||
return *this << QString::fromWCharArray(s.data(), s.size()); // ### optimize
|
||||
}
|
||||
|
||||
template <typename...Args>
|
||||
QDebug &operator<<(std::basic_string_view<wchar_t, Args...> s)
|
||||
{
|
||||
if constexpr (sizeof(wchar_t) == 2)
|
||||
return *this << QStringView(s);
|
||||
else
|
||||
return *this << QString::fromWCharArray(s.data(), s.size()); // ### optimize
|
||||
}
|
||||
|
||||
template <typename...Args>
|
||||
QDebug &operator<<(const std::basic_string<char32_t, Args...> &s)
|
||||
{ return *this << QString::fromUcs4(s.data(), s.size()); }
|
||||
|
||||
inline QDebug &operator<<(std::u32string_view s)
|
||||
template <typename...Args>
|
||||
QDebug &operator<<(std::basic_string_view<char32_t, Args...> s)
|
||||
{ return *this << QString::fromUcs4(s.data(), s.size()); }
|
||||
#endif // !Q_QDOC
|
||||
|
||||
template <typename T>
|
||||
static QString toString(T &&object)
|
||||
|
@ -16,6 +16,13 @@
|
||||
#include <QMimeDatabase>
|
||||
#include <QMetaType>
|
||||
|
||||
#ifdef __cpp_lib_memory_resource
|
||||
# include <memory_resource>
|
||||
namespace pmr = std::pmr;
|
||||
#else
|
||||
namespace pmr = std;
|
||||
#endif
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
static_assert(QTypeTraits::has_ostream_operator_v<QDebug, int>);
|
||||
@ -67,6 +74,8 @@ private slots:
|
||||
void qDebugStdStringView() const;
|
||||
void qDebugStdWString() const;
|
||||
void qDebugStdWStringView() const;
|
||||
void qDebugStdU8String() const;
|
||||
void qDebugStdU8StringView() const;
|
||||
void qDebugStdU16String() const;
|
||||
void qDebugStdU16StringView() const;
|
||||
void qDebugStdU32String() const;
|
||||
@ -663,7 +672,7 @@ void tst_QDebug::qDebugStdString() const
|
||||
MessageHandlerSetter mhs(myMessageHandler);
|
||||
{
|
||||
QDebug d = qDebug();
|
||||
d << std::string("foo") << std::string("") << std::string("barbaz", 3);
|
||||
d << pmr::string("foo") << std::string("") << std::string("barbaz", 3);
|
||||
d.nospace().noquote() << std::string("baz");
|
||||
}
|
||||
#ifndef QT_NO_MESSAGELOGCONTEXT
|
||||
@ -725,7 +734,7 @@ void tst_QDebug::qDebugStdWString() const
|
||||
MessageHandlerSetter mhs(myMessageHandler);
|
||||
{
|
||||
QDebug d = qDebug();
|
||||
d << std::wstring(L"foo") << std::wstring(L"") << std::wstring(L"barbaz", 3);
|
||||
d << pmr::wstring(L"foo") << std::wstring(L"") << std::wstring(L"barbaz", 3);
|
||||
d.nospace().noquote() << std::wstring(L"baz");
|
||||
}
|
||||
#ifndef QT_NO_MESSAGELOGCONTEXT
|
||||
@ -780,6 +789,76 @@ void tst_QDebug::qDebugStdWStringView() const
|
||||
QCOMPARE(s_msg, " " + QString::fromStdWString(std::wstring(string)));
|
||||
}
|
||||
|
||||
void tst_QDebug::qDebugStdU8String() const
|
||||
{
|
||||
#ifndef __cpp_lib_char8_t
|
||||
QSKIP("This test requires C++20 char8_t support enabled in the compiler.");
|
||||
#else
|
||||
QString file, function;
|
||||
int line = 0;
|
||||
MessageHandlerSetter mhs(myMessageHandler);
|
||||
{
|
||||
QDebug d = qDebug();
|
||||
d << pmr::u8string(u8"foo") << std::u8string(u8"") << std::u8string(u8"barbaz", 3);
|
||||
d.nospace().noquote() << std::u8string(u8"baz");
|
||||
}
|
||||
#ifndef QT_NO_MESSAGELOGCONTEXT
|
||||
file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
|
||||
#endif
|
||||
QCOMPARE(s_msgType, QtDebugMsg);
|
||||
QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
|
||||
QCOMPARE(QString::fromLatin1(s_file), file);
|
||||
QCOMPARE(s_line, line);
|
||||
QCOMPARE(QString::fromLatin1(s_function), function);
|
||||
|
||||
/* simpler tests from now on */
|
||||
std::u8string string(u8"\"Hello\"");
|
||||
qDebug() << string;
|
||||
QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
|
||||
|
||||
qDebug().noquote().nospace() << string;
|
||||
QCOMPARE(s_msg, QUtf8StringView(string).toString());
|
||||
|
||||
qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
|
||||
QCOMPARE(s_msg, " " + QUtf8StringView(string).toString());
|
||||
#endif // __cpp_lib_char8_t
|
||||
}
|
||||
|
||||
void tst_QDebug::qDebugStdU8StringView() const
|
||||
{
|
||||
#ifndef __cpp_lib_char8_t
|
||||
QSKIP("This test requires C++20 char8_t support enabled in the compiler.");
|
||||
#else
|
||||
QString file, function;
|
||||
int line = 0;
|
||||
MessageHandlerSetter mhs(myMessageHandler);
|
||||
{
|
||||
QDebug d = qDebug();
|
||||
d << std::u16string_view(u"foo") << std::u16string_view(u"") << std::u16string_view(u"barbaz", 3);
|
||||
d.nospace().noquote() << std::u16string_view(u"baz");
|
||||
}
|
||||
#ifndef QT_NO_MESSAGELOGCONTEXT
|
||||
file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
|
||||
#endif
|
||||
QCOMPARE(s_msgType, QtDebugMsg);
|
||||
QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
|
||||
QCOMPARE(QString::fromLatin1(s_file), file);
|
||||
QCOMPARE(s_line, line);
|
||||
QCOMPARE(QString::fromLatin1(s_function), function);
|
||||
|
||||
/* simpler tests from now on */
|
||||
std::u16string_view string(u"\"Hello\"");
|
||||
qDebug() << string;
|
||||
QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
|
||||
|
||||
qDebug().noquote().nospace() << string;
|
||||
QCOMPARE(s_msg, QString::fromStdU16String(std::u16string(string)));
|
||||
|
||||
qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
|
||||
QCOMPARE(s_msg, " " + QString::fromStdU16String(std::u16string(string)));
|
||||
#endif // __cpp_lib_char8_t
|
||||
}
|
||||
|
||||
void tst_QDebug::qDebugStdU16String() const
|
||||
{
|
||||
QString file, function;
|
||||
@ -787,7 +866,7 @@ void tst_QDebug::qDebugStdU16String() const
|
||||
MessageHandlerSetter mhs(myMessageHandler);
|
||||
{
|
||||
QDebug d = qDebug();
|
||||
d << std::u16string(u"foo") << std::u16string(u"") << std::u16string(u"barbaz", 3);
|
||||
d << pmr::u16string(u"foo") << std::u16string(u"") << std::u16string(u"barbaz", 3);
|
||||
d.nospace().noquote() << std::u16string(u"baz");
|
||||
}
|
||||
#ifndef QT_NO_MESSAGELOGCONTEXT
|
||||
@ -849,7 +928,7 @@ void tst_QDebug::qDebugStdU32String() const
|
||||
MessageHandlerSetter mhs(myMessageHandler);
|
||||
{
|
||||
QDebug d = qDebug();
|
||||
d << std::u32string(U"foo") << std::u32string(U"") << std::u32string(U"barbaz", 3);
|
||||
d << pmr::u32string(U"foo") << std::u32string(U"") << std::u32string(U"barbaz", 3);
|
||||
d.nospace().noquote() << std::u32string(U"baz");
|
||||
}
|
||||
#ifndef QT_NO_MESSAGELOGCONTEXT
|
||||
|
Loading…
Reference in New Issue
Block a user