diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index 61d67ecee5..baef75b234 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -765,75 +765,20 @@ QDebug &QDebug::resetFormat() /*! \since 6.5 - \fn QDebug &QDebug::operator<<(const std::string &s) + \fn template QDebug &QDebug::operator<<(const std::basic_string &s) + \fn template QDebug &QDebug::operator<<(std::basic_string_view 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 */ /*! diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index eccd063ba3..d8db9a8162 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -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 + QDebug &operator<<(const std::basic_string &s); + + template + QDebug &operator<<(std::basic_string_view s); +#else + template + QDebug &operator<<(const std::basic_string &s) { return *this << QUtf8StringView(s); } - inline QDebug &operator<<(std::string_view s) + template + QDebug &operator<<(std::basic_string_view s) { return *this << QUtf8StringView(s); } - inline QDebug &operator<<(const std::wstring &s) - { return *this << QString::fromStdWString(s); } +#ifdef __cpp_char8_t + template + QDebug &operator<<(const std::basic_string &s) + { return *this << QUtf8StringView(s); } - inline QDebug &operator<<(std::wstring_view s) - { return *this << QString::fromWCharArray(s.data(), s.size()); } + template + QDebug &operator<<(std::basic_string_view s) + { return *this << QUtf8StringView(s); } +#endif // __cpp_char8_t - inline QDebug &operator<<(const std::u16string &s) + template + QDebug &operator<<(const std::basic_string &s) { return *this << QStringView(s); } - inline QDebug &operator<<(std::u16string_view s) + template + QDebug &operator<<(std::basic_string_view s) { return *this << QStringView(s); } - inline QDebug &operator<<(const std::u32string &s) + template + QDebug &operator<<(const std::basic_string &s) + { + if constexpr (sizeof(wchar_t) == 2) + return *this << QStringView(s); + else + return *this << QString::fromWCharArray(s.data(), s.size()); // ### optimize + } + + template + QDebug &operator<<(std::basic_string_view s) + { + if constexpr (sizeof(wchar_t) == 2) + return *this << QStringView(s); + else + return *this << QString::fromWCharArray(s.data(), s.size()); // ### optimize + } + + template + QDebug &operator<<(const std::basic_string &s) { return *this << QString::fromUcs4(s.data(), s.size()); } - inline QDebug &operator<<(std::u32string_view s) + template + QDebug &operator<<(std::basic_string_view s) { return *this << QString::fromUcs4(s.data(), s.size()); } +#endif // !Q_QDOC template static QString toString(T &&object) diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp index 077bc58259..a54018c3fa 100644 --- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp +++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp @@ -16,6 +16,13 @@ #include #include +#ifdef __cpp_lib_memory_resource +# include +namespace pmr = std::pmr; +#else +namespace pmr = std; +#endif + using namespace Qt::StringLiterals; static_assert(QTypeTraits::has_ostream_operator_v); @@ -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