diff --git a/src/corelib/text/qstringbuilder.h b/src/corelib/text/qstringbuilder.h index a5a6505628..fb44a56633 100644 --- a/src/corelib/text/qstringbuilder.h +++ b/src/corelib/text/qstringbuilder.h @@ -30,7 +30,10 @@ protected: static void appendLatin1To(QLatin1StringView in, QChar *out) noexcept; }; -template struct QConcatenable {}; +template struct QConcatenable; + +template +using QConcatenableEx = QConcatenable>; namespace QtStringBuilder { template struct ConvertToTypeHelper @@ -72,10 +75,20 @@ struct QStringBuilderBase : public QStringBuilderCommon -class QStringBuilder : public QStringBuilderBase, typename QtStringBuilder::ConvertToTypeHelper::ConvertTo, typename QConcatenable::ConvertTo>::ConvertTo> +class QStringBuilder : public QStringBuilderBase, + typename QtStringBuilder::ConvertToTypeHelper< + typename QConcatenableEx::ConvertTo, + typename QConcatenableEx::ConvertTo + >::ConvertTo + > { public: - QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {} + QStringBuilder(A &&a_, B &&b_) : a(std::forward(a_)), b(std::forward(b_)) {} + + QStringBuilder(QStringBuilder &&) = default; + QStringBuilder(const QStringBuilder &) = default; + ~QStringBuilder() = default; + private: friend class QByteArray; friend class QString; @@ -116,8 +129,12 @@ public: return QtStringBuilder::isNull(a) && QtStringBuilder::isNull(b); } - const A &a; - const B &b; + A a; + B b; + +private: + QStringBuilder &operator=(QStringBuilder &&) = delete; + QStringBuilder &operator=(const QStringBuilder &) = delete; }; template <> struct QConcatenable : private QAbstractConcatenable @@ -361,34 +378,37 @@ template struct QConcatenable< QStringBuilder > { typedef QStringBuilder type; - typedef typename QtStringBuilder::ConvertToTypeHelper::ConvertTo, typename QConcatenable::ConvertTo>::ConvertTo ConvertTo; - enum { ExactSize = QConcatenable::ExactSize && QConcatenable::ExactSize }; + using ConvertTo = typename QtStringBuilder::ConvertToTypeHelper< + typename QConcatenableEx::ConvertTo, + typename QConcatenableEx::ConvertTo + >::ConvertTo; + enum { ExactSize = QConcatenableEx::ExactSize && QConcatenableEx::ExactSize }; static qsizetype size(const type &p) { - return QConcatenable::size(p.a) + QConcatenable::size(p.b); + return QConcatenableEx::size(p.a) + QConcatenableEx::size(p.b); } template static inline void appendTo(const type &p, T *&out) { - QConcatenable::appendTo(p.a, out); - QConcatenable::appendTo(p.b, out); + QConcatenableEx::appendTo(p.a, out); + QConcatenableEx::appendTo(p.b, out); } }; -template -QStringBuilder::type, typename QConcatenable::type> -operator%(const A &a, const B &b) +template ::type, typename QConcatenableEx::type>> +auto operator%(A &&a, B &&b) { - return QStringBuilder::type, typename QConcatenable::type>(a, b); + return QStringBuilder(std::forward(a), std::forward(b)); } // QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards // QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER) -template -QStringBuilder::type, typename QConcatenable::type> -operator+(const A &a, const B &b) +template ::type, typename QConcatenableEx::type>> +auto operator+(A &&a, B &&b) { - return QStringBuilder::type, typename QConcatenable::type>(a, b); + return std::forward(a) % std::forward(b); } #endif diff --git a/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp index a547205460..06dc1ec5a5 100644 --- a/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp +++ b/tests/auto/corelib/text/qstringbuilder/qstringbuilder1/stringbuilder.cpp @@ -98,6 +98,152 @@ void checkNullVsEmpty(const String &empty) QVERIFY(result.isNull()); } +namespace CheckAuto { +// T is cvref-qualified, using universal reference deduction rules. +template struct Helper; + +// These specializations forward to the non-const ones, and add const on top. +template struct Helper +{ + static const T create() { return Helper::create(); } + static const T createNull() { return Helper::createNull(); } +}; +template struct Helper +{ + static const T &create() { return Helper::create(); } + static const T &createNull() { return Helper::createNull(); } +}; + +template <> struct Helper +{ + static QString create() { return QString::fromUtf8("QString rvalue"); } + static QString createNull() { return QString(); } +}; + +template <> struct Helper +{ + static QString &create() { static QString s = QString::fromUtf8("QString lvalue"); return s; } + static QString &createNull() { static QString s; return s; } +}; + +template <> struct Helper +{ + static QStringView create() { return QStringView(u"QStringView rvalue"); } + static QStringView createNull() { return QStringView(); } +}; + +template <> struct Helper +{ + static QStringView &create() { static QStringView s = u"QStringView lvalue"; return s; } + static QStringView &createNull() { static QStringView s; return s; } +}; + +template <> struct Helper +{ + static QByteArray create() { return QByteArray("QByteArray rvalue"); } + static QByteArray createNull() { return QByteArray(); } +}; + +template <> struct Helper +{ + static QByteArray &create() { static QByteArray ba = QByteArray("QByteArray lvalue"); return ba; } + static QByteArray &createNull() { static QByteArray ba; return ba; } +}; + +template <> struct Helper +{ + static QByteArrayView create() { return QByteArrayView("QByteArrayView rvalue"); } + static QByteArrayView createNull() { return QByteArrayView(); } +}; + +template <> struct Helper +{ + static QByteArrayView &create() { static QByteArrayView ba = "QByteArrayView lvalue"; return ba; } + static QByteArrayView &createNull() { static QByteArrayView ba; return ba; } +}; + +template <> struct Helper +{ + static const char *create() { return "const char * rvalue"; } + static const char *createNull() { return ""; } +}; + +template <> struct Helper +{ + static const char *&create() { static const char *s = "const char * lvalue"; return s; } + static const char *&createNull() { static const char *s = ""; return s; } +}; + +template +void checkAutoImpl3() +{ + { + auto result = Helper::create() P Helper::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper::create() P Helper::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper::create() P Helper::create() P Helper::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper::create() P Helper::create() P Helper::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper::createNull() P Helper::create(); + Result expected = result; + QCOMPARE(result, expected); + } + { + auto result = Helper::createNull() P Helper::createNull(); + Result expected = result; + QCOMPARE(result, expected); + } +} + +template +void checkAutoImpl2() +{ + checkAutoImpl3(); + checkAutoImpl3(); + checkAutoImpl3(); + checkAutoImpl3(); +} + +template +void checkAutoImpl() +{ + checkAutoImpl2< String1, String2, Result>(); + checkAutoImpl2(); + checkAutoImpl2< String1, const String2, Result>(); + checkAutoImpl2(); +} + +} // namespace CheckAuto + +void checkAuto() +{ + CheckAuto::checkAutoImpl(); + CheckAuto::checkAutoImpl(); + + CheckAuto::checkAutoImpl(); + CheckAuto::checkAutoImpl(); + CheckAuto::checkAutoImpl(); + +#ifndef QT_NO_CAST_FROM_ASCII + CheckAuto::checkAutoImpl(); + CheckAuto::checkAutoImpl(); +#endif +} + void runScenario() { // this code is latin1. TODO: replace it with the utf8 block below, once @@ -381,6 +527,9 @@ void runScenario() checkNullVsEmpty(QStringLiteral("")); checkNullVsEmpty(QByteArrayLiteral("")); + // auto + checkAuto(); + checkItWorksWithFreeSpaceAtBegin(QByteArray(UTF8_LITERAL), "1234"); if (QTest::currentTestFailed()) return;