/**************************************************************************** ** ** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include // for negative testing (can't convert from) #include #include template using CanConvert = std::is_convertible; static_assert(!CanConvert::value); static_assert(!CanConvert::value); static_assert(!CanConvert::value); // QStringView qchar_does_not_compile() { return QStringView(QChar('a')); } // QStringView qlatin1string_does_not_compile() { return QStringView(QLatin1String("a")); } // QStringView const_char_star_does_not_compile() { return QStringView("a"); } // QStringView qbytearray_does_not_compile() { return QStringView(QByteArray("a")); } // // QChar // static_assert(!CanConvert::value); static_assert(CanConvert::value); static_assert(CanConvert< QString >::value); static_assert(CanConvert::value); static_assert(CanConvert< QString&>::value); static_assert(CanConvert::value); // // ushort // static_assert(!CanConvert::value); static_assert(CanConvert::value); static_assert(CanConvert< ushort*>::value); static_assert(CanConvert::value); static_assert(CanConvert>::value); static_assert(CanConvert>::value); static_assert(CanConvert>::value); static_assert(CanConvert>::value); static_assert(!CanConvert>::value); static_assert(!CanConvert>::value); // // char16_t // static_assert(!CanConvert::value); static_assert(CanConvert< char16_t*>::value); static_assert(CanConvert::value); static_assert(CanConvert< std::u16string >::value); static_assert(CanConvert::value); static_assert(CanConvert< std::u16string&>::value); static_assert(CanConvert::value); static_assert(CanConvert< std::u16string_view >::value); static_assert(CanConvert::value); static_assert(CanConvert< std::u16string_view&>::value); static_assert(CanConvert::value); static_assert(CanConvert>::value); static_assert(CanConvert>::value); static_assert(CanConvert>::value); static_assert(CanConvert>::value); static_assert(!CanConvert>::value); static_assert(!CanConvert>::value); // // wchar_t // constexpr bool CanConvertFromWCharT = #ifdef Q_OS_WIN true #else false #endif ; static_assert(!CanConvert::value); static_assert(CanConvert< wchar_t*>::value == CanConvertFromWCharT); static_assert(CanConvert::value == CanConvertFromWCharT); static_assert(CanConvert< std::wstring >::value == CanConvertFromWCharT); static_assert(CanConvert::value == CanConvertFromWCharT); static_assert(CanConvert< std::wstring&>::value == CanConvertFromWCharT); static_assert(CanConvert::value == CanConvertFromWCharT); static_assert(CanConvert< std::wstring_view >::value == CanConvertFromWCharT); static_assert(CanConvert::value == CanConvertFromWCharT); static_assert(CanConvert< std::wstring_view&>::value == CanConvertFromWCharT); static_assert(CanConvert::value == CanConvertFromWCharT); static_assert(CanConvert>::value == CanConvertFromWCharT); static_assert(CanConvert>::value == CanConvertFromWCharT); static_assert(CanConvert>::value == CanConvertFromWCharT); static_assert(CanConvert>::value == CanConvertFromWCharT); static_assert(!CanConvert>::value); static_assert(!CanConvert>::value); class tst_QStringView : public QObject { Q_OBJECT private Q_SLOTS: void constExpr() const; void basics() const; void literals() const; void at() const; void arg() const; void fromQString() const; void fromQCharStar() const { const QChar str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 }; fromLiteral(str); } void fromUShortStar() const { const ushort str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 }; fromLiteral(str); } void fromChar16TStar() const { fromLiteral(u"Hello, World!"); } void fromWCharTStar() const { #ifdef Q_OS_WIN fromLiteral(L"Hello, World!"); #else QSKIP("This is a Windows-only test"); #endif } void fromQCharRange() const { const QChar str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; fromRange(std::begin(str), std::end(str)); } void fromUShortRange() const { const ushort str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; fromRange(std::begin(str), std::end(str)); } void fromChar16TRange() const { const char16_t str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; fromRange(std::begin(str), std::end(str)); } void fromWCharTRange() const { #ifdef Q_OS_WIN const wchar_t str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; fromRange(std::begin(str), std::end(str)); #else QSKIP("This is a Windows-only test"); #endif } // std::basic_string void fromStdStringWCharT() const { #ifdef Q_OS_WIN fromStdString(); #else QSKIP("This is a Windows-only test"); #endif } void fromStdStringChar16T() const { fromStdString(); } void fromUShortContainers() const { fromContainers(); } void fromQCharContainers() const { fromContainers(); } void fromChar16TContainers() const { fromContainers(); } void fromWCharTContainers() const { #ifdef Q_OS_WIN fromContainers(); #else QSKIP("This is a Windows-only test"); #endif } void comparison(); void overloadResolution(); void tokenize_data() const; void tokenize() const; private: template void conversion_tests(String arg) const; template void fromLiteral(const Char *arg) const; template void fromRange(const Char *first, const Char *last) const; template void fromContainer() const; template void fromContainers() const; template void fromStdString() const { fromContainer >(); } }; void tst_QStringView::constExpr() const { // compile-time checks #ifdef Q_COMPILER_CONSTEXPR { constexpr QStringView sv; static_assert(sv.size() == 0); static_assert(sv.isNull()); static_assert(sv.empty()); static_assert(sv.isEmpty()); static_assert(sv.utf16() == nullptr); constexpr QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); static_assert(sv2.isNull()); static_assert(sv2.empty()); } { constexpr QStringView sv = nullptr; Q_STATIC_ASSERT(sv.size() == 0); Q_STATIC_ASSERT(sv.isNull()); Q_STATIC_ASSERT(sv.empty()); Q_STATIC_ASSERT(sv.isEmpty()); Q_STATIC_ASSERT(sv.utf16() == nullptr); } { constexpr QStringView sv = u""; static_assert(sv.size() == 0); static_assert(!sv.isNull()); static_assert(sv.empty()); static_assert(sv.isEmpty()); static_assert(sv.utf16() != nullptr); constexpr QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); static_assert(!sv2.isNull()); static_assert(sv2.empty()); } { constexpr QStringView sv = u"Hello"; static_assert(sv.size() == 5); static_assert(!sv.empty()); static_assert(!sv.isEmpty()); static_assert(!sv.isNull()); static_assert(*sv.utf16() == 'H'); static_assert(sv[0] == QLatin1Char('H')); static_assert(sv.at(0) == QLatin1Char('H')); static_assert(sv.front() == QLatin1Char('H')); static_assert(sv.first() == QLatin1Char('H')); static_assert(sv[4] == QLatin1Char('o')); static_assert(sv.at(4) == QLatin1Char('o')); static_assert(sv.back() == QLatin1Char('o')); static_assert(sv.last() == QLatin1Char('o')); constexpr QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); static_assert(!sv2.isNull()); static_assert(!sv2.empty()); static_assert(sv2.size() == 5); } { static_assert(QStringView(u"Hello").size() == 5); constexpr QStringView sv = u"Hello"; static_assert(sv.size() == 5); static_assert(!sv.empty()); static_assert(!sv.isEmpty()); static_assert(!sv.isNull()); static_assert(*sv.utf16() == 'H'); static_assert(sv[0] == QLatin1Char('H')); static_assert(sv.at(0) == QLatin1Char('H')); static_assert(sv.front() == QLatin1Char('H')); static_assert(sv.first() == QLatin1Char('H')); static_assert(sv[4] == QLatin1Char('o')); static_assert(sv.at(4) == QLatin1Char('o')); static_assert(sv.back() == QLatin1Char('o')); static_assert(sv.last() == QLatin1Char('o')); constexpr QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); static_assert(!sv2.isNull()); static_assert(!sv2.empty()); static_assert(sv2.size() == 5); constexpr char16_t *null = nullptr; constexpr QStringView sv3(null); static_assert(sv3.isNull()); static_assert(sv3.isEmpty()); static_assert(sv3.size() == 0); } #endif } void tst_QStringView::basics() const { QStringView sv1; // a default-constructed QStringView is null: QVERIFY(sv1.isNull()); // which implies it's empty(); QVERIFY(sv1.isEmpty()); QStringView sv2; QVERIFY(sv2 == sv1); QVERIFY(!(sv2 != sv1)); } void tst_QStringView::literals() const { const char16_t hello[] = u"Hello"; const char16_t longhello[] = u"Hello World. This is a much longer message, to exercise qustrlen."; const char16_t withnull[] = u"a\0zzz"; static_assert(sizeof(longhello) >= 16); QCOMPARE(QStringView(hello).size(), 5); QCOMPARE(QStringView(hello + 0).size(), 5); // forces decay to pointer QStringView sv = hello; QCOMPARE(sv.size(), 5); QVERIFY(!sv.empty()); QVERIFY(!sv.isEmpty()); QVERIFY(!sv.isNull()); QCOMPARE(*sv.utf16(), 'H'); QCOMPARE(sv[0], QLatin1Char('H')); QCOMPARE(sv.at(0), QLatin1Char('H')); QCOMPARE(sv.front(), QLatin1Char('H')); QCOMPARE(sv.first(), QLatin1Char('H')); QCOMPARE(sv[4], QLatin1Char('o')); QCOMPARE(sv.at(4), QLatin1Char('o')); QCOMPARE(sv.back(), QLatin1Char('o')); QCOMPARE(sv.last(), QLatin1Char('o')); QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); QVERIFY(!sv2.isNull()); QVERIFY(!sv2.empty()); QCOMPARE(sv2.size(), 5); QStringView sv3(longhello); QCOMPARE(size_t(sv3.size()), sizeof(longhello)/sizeof(longhello[0]) - 1); QCOMPARE(sv3.last(), QLatin1Char('.')); sv3 = longhello; QCOMPARE(size_t(sv3.size()), sizeof(longhello)/sizeof(longhello[0]) - 1); for (int i = 0; i < sv3.size(); ++i) { QStringView sv4(longhello + i); QCOMPARE(size_t(sv4.size()), sizeof(longhello)/sizeof(longhello[0]) - 1 - i); QCOMPARE(sv4.last(), QLatin1Char('.')); sv4 = longhello + i; QCOMPARE(size_t(sv4.size()), sizeof(longhello)/sizeof(longhello[0]) - 1 - i); } // these are different results QCOMPARE(size_t(QStringView(withnull).size()), sizeof(withnull)/sizeof(withnull[0]) - 1); QCOMPARE(QStringView(withnull + 0).size(), 1); } void tst_QStringView::at() const { QString hello("Hello"); QStringView sv(hello); QCOMPARE(sv.at(0), QChar('H')); QCOMPARE(sv[0], QChar('H')); QCOMPARE(sv.at(1), QChar('e')); QCOMPARE(sv[1], QChar('e')); QCOMPARE(sv.at(2), QChar('l')); QCOMPARE(sv[2], QChar('l')); QCOMPARE(sv.at(3), QChar('l')); QCOMPARE(sv[3], QChar('l')); QCOMPARE(sv.at(4), QChar('o')); QCOMPARE(sv[4], QChar('o')); } void tst_QStringView::arg() const { #define CHECK1(pattern, arg1, expected) \ do { \ auto p = QStringView(u"" pattern); \ QCOMPARE(p.arg(QLatin1String(arg1)), expected); \ QCOMPARE(p.arg(u"" arg1), expected); \ QCOMPARE(p.arg(QStringLiteral(arg1)), expected); \ QCOMPARE(p.arg(QString(QLatin1String(arg1))), expected); \ } while (false) \ /*end*/ #define CHECK2(pattern, arg1, arg2, expected) \ do { \ auto p = QStringView(u"" pattern); \ QCOMPARE(p.arg(QLatin1String(arg1), QLatin1String(arg2)), expected); \ QCOMPARE(p.arg(u"" arg1, QLatin1String(arg2)), expected); \ QCOMPARE(p.arg(QLatin1String(arg1), u"" arg2), expected); \ QCOMPARE(p.arg(u"" arg1, u"" arg2), expected); \ } while (false) \ /*end*/ CHECK1("", "World", ""); CHECK1("%1", "World", "World"); CHECK1("!%1?", "World", "!World?"); CHECK1("%1%1", "World", "WorldWorld"); CHECK1("%1%2", "World", "World%2"); CHECK1("%2%1", "World", "%2World"); CHECK2("", "Hello", "World", ""); CHECK2("%1", "Hello", "World", "Hello"); CHECK2("!%1, %2?", "Hello", "World", "!Hello, World?"); CHECK2("%1%1", "Hello", "World", "HelloHello"); CHECK2("%1%2", "Hello", "World", "HelloWorld"); CHECK2("%2%1", "Hello", "World", "WorldHello"); #undef CHECK2 #undef CHECK1 QCOMPARE(QStringView(u" %2 %2 %1 %3 ").arg(QLatin1Char('c'), QChar::CarriageReturn, u'C'), " \r \r c C "); } void tst_QStringView::fromQString() const { QString null; QString empty = ""; QVERIFY( QStringView(null).isNull()); QVERIFY( QStringView(null).isEmpty()); QVERIFY( QStringView(empty).isEmpty()); QVERIFY(!QStringView(empty).isNull()); conversion_tests(QString("Hello World!")); } void tst_QStringView::tokenize_data() const { // copied from tst_QString QTest::addColumn("str"); QTest::addColumn("sep"); QTest::addColumn("result"); QTest::newRow("1") << "a,b,c" << "," << (QStringList() << "a" << "b" << "c"); QTest::newRow("2") << QString("-rw-r--r-- 1 0 0 519240 Jul 9 2002 bigfile") << " " << (QStringList() << "-rw-r--r--" << "" << "1" << "0" << "" << "0" << "" << "519240" << "Jul" << "" << "9" << "" << "2002" << "bigfile"); QTest::newRow("one-empty") << "" << " " << (QStringList() << ""); QTest::newRow("two-empty") << " " << " " << (QStringList() << "" << ""); QTest::newRow("three-empty") << " " << " " << (QStringList() << "" << "" << ""); QTest::newRow("all-empty") << "" << "" << (QStringList() << "" << ""); QTest::newRow("sep-empty") << "abc" << "" << (QStringList() << "" << "a" << "b" << "c" << ""); } void tst_QStringView::tokenize() const { QFETCH(const QString, str); QFETCH(const QString, sep); QFETCH(const QStringList, result); // lvalue QString #ifdef __cpp_deduction_guides { auto rit = result.cbegin(); for (auto sv : QStringTokenizer{str, sep}) QCOMPARE(sv, *rit++); } #endif { auto rit = result.cbegin(); for (auto sv : QStringView{str}.tokenize(sep)) QCOMPARE(sv, *rit++); } // rvalue QString #ifdef __cpp_deduction_guides { auto rit = result.cbegin(); for (auto sv : QStringTokenizer{str, QString{sep}}) QCOMPARE(sv, *rit++); } #endif { auto rit = result.cbegin(); for (auto sv : QStringView{str}.tokenize(QString{sep})) QCOMPARE(sv, *rit++); } // (rvalue) QChar #ifdef __cpp_deduction_guides if (sep.size() == 1) { auto rit = result.cbegin(); for (auto sv : QStringTokenizer{str, sep.front()}) QCOMPARE(sv, *rit++); } #endif if (sep.size() == 1) { auto rit = result.cbegin(); for (auto sv : QStringView{str}.tokenize(sep.front())) QCOMPARE(sv, *rit++); } // (rvalue) char16_t #ifdef __cpp_deduction_guides if (sep.size() == 1) { auto rit = result.cbegin(); for (auto sv : QStringTokenizer{str, *qToStringViewIgnoringNull(sep).utf16()}) QCOMPARE(sv, *rit++); } #endif if (sep.size() == 1) { auto rit = result.cbegin(); for (auto sv : QStringView{str}.tokenize(*qToStringViewIgnoringNull(sep).utf16())) QCOMPARE(sv, *rit++); } // char16_t literal const auto make_literal = [](const QString &sep) { auto literal = std::make_unique(sep.size() + 1); const auto to_char16_t = [](QChar c) { return char16_t{c.unicode()}; }; std::transform(sep.cbegin(), sep.cend(), literal.get(), to_char16_t); return literal; }; const std::unique_ptr literal = make_literal(sep); #ifdef __cpp_deduction_guides { auto rit = result.cbegin(); for (auto sv : QStringTokenizer{str, literal.get()}) QCOMPARE(sv, *rit++); } #endif { auto rit = result.cbegin(); for (auto sv : QStringView{str}.tokenize(literal.get())) QCOMPARE(sv, *rit++); } #ifdef __cpp_deduction_guides #ifdef __cpp_lib_ranges // lvalue QString { QStringList actual; const QStringTokenizer tok{str, sep}; std::ranges::transform(tok, std::back_inserter(actual), [](auto sv) { return sv.toString(); }); QCOMPARE(result, actual); } // rvalue QString { QStringList actual; const QStringTokenizer tok{str, QString{sep}}; std::ranges::transform(tok, std::back_inserter(actual), [](auto sv) { return sv.toString(); }); QCOMPARE(result, actual); } // (rvalue) QChar if (sep.size() == 1) { QStringList actual; const QStringTokenizer tok{str, sep.front()}; std::ranges::transform(tok, std::back_inserter(actual), [](auto sv) { return sv.toString(); }); QCOMPARE(result, actual); } #endif // __cpp_lib_ranges #endif // __cpp_deduction_guides } template void tst_QStringView::fromLiteral(const Char *arg) const { const Char *null = nullptr; const Char empty[] = { 0 }; QCOMPARE(QStringView(null).size(), qsizetype(0)); QCOMPARE(QStringView(null).data(), nullptr); QCOMPARE(QStringView(empty).size(), qsizetype(0)); QCOMPARE(static_cast(QStringView(empty).data()), static_cast(empty)); QVERIFY( QStringView(null).isNull()); QVERIFY( QStringView(null).isEmpty()); QVERIFY( QStringView(empty).isEmpty()); QVERIFY(!QStringView(empty).isNull()); conversion_tests(arg); } template void tst_QStringView::fromRange(const Char *first, const Char *last) const { const Char *null = nullptr; QCOMPARE(QStringView(null, null).size(), 0); QCOMPARE(QStringView(null, null).data(), nullptr); QCOMPARE(QStringView(first, first).size(), 0); QCOMPARE(static_cast(QStringView(first, first).data()), static_cast(first)); const auto sv = QStringView(first, last); QCOMPARE(sv.size(), last - first); QCOMPARE(static_cast(sv.data()), static_cast(first)); // can't call conversion_tests() here, as it requires a single object } template void tst_QStringView::fromContainer() const { const QString s = "Hello World!"; Container c; // unspecified whether empty containers make null QStringViews QVERIFY(QStringView(c).isEmpty()); QCOMPARE(sizeof(Char), sizeof(QChar)); const auto *data = reinterpret_cast(s.utf16()); std::copy(data, data + s.size(), std::back_inserter(c)); conversion_tests(std::move(c)); } template void tst_QStringView::fromContainers() const { fromContainer>(); fromContainer>(); fromContainer>(); } namespace help { template size_t size(const T &t) { return size_t(t.size()); } template size_t size(const T *t) { size_t result = 0; if (t) { while (*t++) ++result; } return result; } size_t size(const QChar *t) { size_t result = 0; if (t) { while (!t++->isNull()) ++result; } return result; } template decltype(auto) cbegin(const T &t) { return t.begin(); } template const T * cbegin(const T *t) { return t; } template decltype(auto) cend(const T &t) { return t.end(); } template const T * cend(const T *t) { return t + size(t); } template decltype(auto) crbegin(const T &t) { return t.rbegin(); } template std::reverse_iterator crbegin(const T *t) { return std::reverse_iterator(cend(t)); } template decltype(auto) crend(const T &t) { return t.rend(); } template std::reverse_iterator crend(const T *t) { return std::reverse_iterator(cbegin(t)); } } // namespace help template void tst_QStringView::conversion_tests(String string) const { // copy-construct: { QStringView sv = string; QCOMPARE(help::size(sv), help::size(string)); // check iterators: QVERIFY(std::equal(help::cbegin(string), help::cend(string), QT_MAKE_CHECKED_ARRAY_ITERATOR(sv.cbegin(), sv.size()))); QVERIFY(std::equal(help::cbegin(string), help::cend(string), QT_MAKE_CHECKED_ARRAY_ITERATOR(sv.begin(), sv.size()))); QVERIFY(std::equal(help::crbegin(string), help::crend(string), sv.crbegin())); QVERIFY(std::equal(help::crbegin(string), help::crend(string), sv.rbegin())); QCOMPARE(sv, string); } QStringView sv; // copy-assign: { sv = string; QCOMPARE(help::size(sv), help::size(string)); // check relational operators: QCOMPARE(sv, string); QCOMPARE(string, sv); QVERIFY(!(sv != string)); QVERIFY(!(string != sv)); QVERIFY(!(sv < string)); QVERIFY(sv <= string); QVERIFY(!(sv > string)); QVERIFY(sv >= string); QVERIFY(!(string < sv)); QVERIFY(string <= sv); QVERIFY(!(string > sv)); QVERIFY(string >= sv); } // copy-construct from rvalue (QStringView never assumes ownership): { QStringView sv2 = std::move(string); QCOMPARE(sv2, sv); QCOMPARE(sv2, string); } // copy-assign from rvalue (QStringView never assumes ownership): { QStringView sv2; sv2 = std::move(string); QCOMPARE(sv2, sv); QCOMPARE(sv2, string); } } void tst_QStringView::comparison() { const QStringView aa = u"aa"; const QStringView upperAa = u"AA"; const QStringView bb = u"bb"; QVERIFY(aa == aa); QVERIFY(aa != bb); QVERIFY(aa < bb); QVERIFY(bb > aa); QCOMPARE(aa.compare(aa), 0); QVERIFY(aa.compare(upperAa) != 0); QCOMPARE(aa.compare(upperAa, Qt::CaseInsensitive), 0); QVERIFY(aa.compare(bb) < 0); QVERIFY(bb.compare(aa) > 0); } namespace QStringViewOverloadResolution { static void test(QString) = delete; static void test(QStringView) {} } // Compile-time only test: overload resolution prefers QStringView over QString void tst_QStringView::overloadResolution() { { QChar qcharArray[42] = {}; QStringViewOverloadResolution::test(qcharArray); QChar *qcharPointer = qcharArray; QStringViewOverloadResolution::test(qcharPointer); } { ushort ushortArray[42] = {}; QStringViewOverloadResolution::test(ushortArray); ushort *ushortPointer = ushortArray; QStringViewOverloadResolution::test(ushortPointer); } #if defined(Q_OS_WIN) { wchar_t wchartArray[42] = {}; QStringViewOverloadResolution::test(wchartArray); QStringViewOverloadResolution::test(L"test"); } #endif { char16_t char16Array[] = u"test"; QStringViewOverloadResolution::test(char16Array); char16_t *char16Pointer = char16Array; QStringViewOverloadResolution::test(char16Pointer); } { std::u16string string; QStringViewOverloadResolution::test(string); QStringViewOverloadResolution::test(qAsConst(string)); QStringViewOverloadResolution::test(std::move(string)); } } QTEST_APPLESS_MAIN(tst_QStringView) #include "tst_qstringview.moc"