Extend QString::arg(QString, ..., QString) to more than 9 arguments

Now that we have QStringView::arg(), we can use it to implement a
similarly flexible QString::arg(). It's not as straight-forward as in
QStringView, though: QString has existing arg() overloads that all
become worse matches with the introduction of the new,
perfectly-forwarding overload.

So in order to allow calling of the other arg() functions, first
constrain the new arg() function to arguments that are convertible to
QString, QStringView, or QLatin1String, and then delegate to the
QStringView version. To stay compatible with the previous overloads,
which accepted anything that implicitly converts to QString (in
particular, QStringBuilder expressions), add a new overload of
qStringLikeToView, taking const QString &. This benefits the existing
QStringView and QLatin1View versions, too.

[ChangeLog][QtCore][QString] QString::arg(QString, ..., QString) can
now be called with more than nine arguments, as well as with
QStringViews.

Change-Id: I1e717a1bc696346808bcae45dc47762a492c8714
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Marc Mutz 2017-01-07 21:58:01 +01:00
parent ca5fc087bd
commit fd42589b14
2 changed files with 38 additions and 2 deletions

View File

@ -89,6 +89,10 @@ class QTextCodec;
class QStringRef; class QStringRef;
template <typename T> class QVector; template <typename T> class QVector;
namespace QtPrivate {
template <bool...B> class BoolList;
}
class QLatin1String class QLatin1String
{ {
public: public:
@ -333,6 +337,7 @@ public:
QChar fillChar = QLatin1Char(' ')) const; QChar fillChar = QLatin1Char(' ')) const;
Q_REQUIRED_RESULT QString arg(QLatin1String a, int fieldWidth = 0, Q_REQUIRED_RESULT QString arg(QLatin1String a, int fieldWidth = 0,
QChar fillChar = QLatin1Char(' ')) const; QChar fillChar = QLatin1Char(' ')) const;
#if QT_STRINGVIEW_LEVEL < 2
Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2) const; Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2) const;
Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2, const QString &a3) const; Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2, const QString &a3) const;
Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2, const QString &a3, Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2, const QString &a3,
@ -350,6 +355,33 @@ public:
Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2, const QString &a3, Q_REQUIRED_RESULT QString arg(const QString &a1, const QString &a2, const QString &a3,
const QString &a4, const QString &a5, const QString &a6, const QString &a4, const QString &a5, const QString &a6,
const QString &a7, const QString &a8, const QString &a9) const; const QString &a7, const QString &a8, const QString &a9) const;
#endif
private:
template <typename T>
struct is_convertible_to_view_or_qstring_helper
: std::integral_constant<bool,
std::is_convertible<T, QString>::value ||
std::is_convertible<T, QStringView>::value ||
std::is_convertible<T, QLatin1String>::value> {};
template <typename T>
struct is_convertible_to_view_or_qstring
: is_convertible_to_view_or_qstring_helper<typename std::decay<T>::type> {};
public:
template <typename...Args>
Q_REQUIRED_RESULT
#ifdef Q_CLANG_QDOC
QString
#else
typename std::enable_if<
sizeof...(Args) >= 2 && std::is_same<
QtPrivate::BoolList<is_convertible_to_view_or_qstring<Args>::value..., true>,
QtPrivate::BoolList<true, is_convertible_to_view_or_qstring<Args>::value...>
>::value,
QString
>::type
#endif
arg(Args &&...args) const
{ return qToStringViewIgnoringNull(*this).arg(std::forward<Args>(args)...); }
#if QT_DEPRECATED_SINCE(5, 14) #if QT_DEPRECATED_SINCE(5, 14)
QT_DEPRECATED_X("Use vasprintf(), arg() or QTextStream instead") QT_DEPRECATED_X("Use vasprintf(), arg() or QTextStream instead")
@ -1053,6 +1085,7 @@ inline QString QString::arg(short a, int fieldWidth, int base, QChar fillChar) c
{ return arg(qlonglong(a), fieldWidth, base, fillChar); } { return arg(qlonglong(a), fieldWidth, base, fillChar); }
inline QString QString::arg(ushort a, int fieldWidth, int base, QChar fillChar) const inline QString QString::arg(ushort a, int fieldWidth, int base, QChar fillChar) const
{ return arg(qulonglong(a), fieldWidth, base, fillChar); } { return arg(qulonglong(a), fieldWidth, base, fillChar); }
#if QT_STRINGVIEW_LEVEL < 2
inline QString QString::arg(const QString &a1, const QString &a2) const inline QString QString::arg(const QString &a1, const QString &a2) const
{ return qToStringViewIgnoringNull(*this).arg(a1, a2); } { return qToStringViewIgnoringNull(*this).arg(a1, a2); }
inline QString QString::arg(const QString &a1, const QString &a2, const QString &a3) const inline QString QString::arg(const QString &a1, const QString &a2, const QString &a3) const
@ -1078,6 +1111,7 @@ inline QString QString::arg(const QString &a1, const QString &a2, const QString
const QString &a4, const QString &a5, const QString &a6, const QString &a4, const QString &a5, const QString &a6,
const QString &a7, const QString &a8, const QString &a9) const const QString &a7, const QString &a8, const QString &a9) const
{ return qToStringViewIgnoringNull(*this).arg(a1, a2, a3, a4, a5, a6, a7, a8, a9); } { return qToStringViewIgnoringNull(*this).arg(a1, a2, a3, a4, a5, a6, a7, a8, a9); }
#endif
inline QString QString::section(QChar asep, int astart, int aend, SectionFlags aflags) const inline QString QString::section(QChar asep, int astart, int aend, SectionFlags aflags) const
{ return section(QString(asep), astart, aend, aflags); } { return section(QString(asep), astart, aend, aflags); }
@ -2014,6 +2048,7 @@ Q_REQUIRED_RESULT Q_ALWAYS_INLINE QString argToQStringDispatch(StringView patter
return QtPrivate::argToQString(pattern, sizeof...(Args), argBases); return QtPrivate::argToQString(pattern, sizeof...(Args), argBases);
} }
inline QStringViewArg qStringLikeToArg(const QString &s) noexcept { return QStringViewArg{qToStringViewIgnoringNull(s)}; }
Q_DECL_CONSTEXPR inline QStringViewArg qStringLikeToArg(QStringView s) noexcept { return QStringViewArg{s}; } Q_DECL_CONSTEXPR inline QStringViewArg qStringLikeToArg(QStringView s) noexcept { return QStringViewArg{s}; }
inline QStringViewArg qStringLikeToArg(const QChar &c) noexcept { return QStringViewArg{QStringView{&c, 1}}; } inline QStringViewArg qStringLikeToArg(const QChar &c) noexcept { return QStringViewArg{QStringView{&c, 1}}; }
Q_DECL_CONSTEXPR inline QLatin1StringArg qStringLikeToArg(QLatin1String s) noexcept { return QLatin1StringArg{s}; } Q_DECL_CONSTEXPR inline QLatin1StringArg qStringLikeToArg(QLatin1String s) noexcept { return QLatin1StringArg{s}; }

View File

@ -532,6 +532,7 @@ QT_BEGIN_NAMESPACE
/*! /*!
\fn QString QStringView::arg(Args &&...args) const \fn QString QStringView::arg(Args &&...args) const
\fn QString QLatin1String::arg(Args &&...args) const \fn QString QLatin1String::arg(Args &&...args) const
\fn QString QString::arg(Args &&...args) const
\since 5.14 \since 5.14
Replaces occurrences of \c{%N} in this string with the corresponding Replaces occurrences of \c{%N} in this string with the corresponding
@ -539,8 +540,8 @@ QT_BEGIN_NAMESPACE
the \a args replaces the \c{%N} with the lowest \c{N} (all of them), the the \a args replaces the \c{%N} with the lowest \c{N} (all of them), the
second of the \a args the \c{%N} with the next-lowest \c{N} etc. second of the \a args the \c{%N} with the next-lowest \c{N} etc.
\c Args can consist of anything that implicitly converts to QStringView \c Args can consist of anything that implicitly converts to QString,
or QLatin1String. QStringView or QLatin1String.
In addition, the following types are also supported: QChar, QLatin1Char. In addition, the following types are also supported: QChar, QLatin1Char.