QChar: fix ambiguous comparisons with 0, '\0', ... for good

Commit e0ea0f6178 optimized QChar <->
QString(Ref) comparisons by adding more overloads to avoid creating
QStrings from QChars just to compare them.

But these new overloads made existing comparisons to QChar ambiguous.
This was known at the time for QChar/int comparisons.

It has since turned out that also comparing to '\0' is ambiguous,
ie. not comparing to int or char per se is ambiguous, but comparing to
nullptr constants is, because QString(const char*) is just as good a
candidate as QChar(char)/QChar(int).

Since we allow QString/QChar comparisons, it seems logical to solve
the problem by adding QChar<->nullptr overloads.

[ChangeLog][QtCore][QChar] Disambiguated comparisons with nullptr
constants such as '\0', which 5.8.0 broke. As a consequence,
QChar<->int comparisons are no longer deprecated, as this was a failed
attempt at fixing the ambiguity.

Change-Id: I680dd509c2286e96894e13078899dbe3b2dd83bc
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Marc Mutz 2017-03-17 11:07:30 +01:00
parent 4ee7425794
commit 5c724a6087
2 changed files with 53 additions and 30 deletions

View File

@ -578,17 +578,21 @@ Q_DECL_CONSTEXPR inline bool operator>=(QChar c1, QChar c2) Q_DECL_NOTHROW { ret
Q_DECL_CONSTEXPR inline bool operator> (QChar c1, QChar c2) Q_DECL_NOTHROW { return operator< (c2, c1); }
Q_DECL_CONSTEXPR inline bool operator<=(QChar c1, QChar c2) Q_DECL_NOTHROW { return !operator< (c2, c1); }
// disambiguate QChar == int (but only that, so constrain template to exactly 'int'):
template <typename T>
Q_DECL_DEPRECATED_X("don't compare ints to QChars, compare them to QChar::unicode() instead")
Q_DECL_CONSTEXPR inline
typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, int>::value, bool>::type
operator==(QChar lhs, T rhs) Q_DECL_NOEXCEPT { return lhs == QChar(rhs); }
template <typename T>
Q_DECL_DEPRECATED_X("don't compare ints to QChars, compare them to QChar::unicode() instead")
Q_DECL_CONSTEXPR inline
typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, int>::value, bool>::type
operator!=(QChar lhs, T rhs) Q_DECL_NOEXCEPT { return lhs != QChar(rhs); }
Q_DECL_CONSTEXPR inline bool operator==(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return lhs.isNull(); }
Q_DECL_CONSTEXPR inline bool operator< (QChar, std::nullptr_t) Q_DECL_NOTHROW { return false; }
Q_DECL_CONSTEXPR inline bool operator==(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return rhs.isNull(); }
Q_DECL_CONSTEXPR inline bool operator< (std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !rhs.isNull(); }
Q_DECL_CONSTEXPR inline bool operator!=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator==(lhs, nullptr); }
Q_DECL_CONSTEXPR inline bool operator>=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator< (lhs, nullptr); }
Q_DECL_CONSTEXPR inline bool operator> (QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return operator< (nullptr, lhs); }
Q_DECL_CONSTEXPR inline bool operator<=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator< (nullptr, lhs); }
Q_DECL_CONSTEXPR inline bool operator!=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator==(nullptr, rhs); }
Q_DECL_CONSTEXPR inline bool operator>=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator< (nullptr, rhs); }
Q_DECL_CONSTEXPR inline bool operator> (std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return operator< (rhs, nullptr); }
Q_DECL_CONSTEXPR inline bool operator<=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator< (rhs, nullptr); }
#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QChar);

View File

@ -36,7 +36,7 @@ class tst_QChar : public QObject
{
Q_OBJECT
private slots:
void operator_eqeq_int();
void operator_eqeq_null();
void operators_data();
void operators();
void toUpper();
@ -72,35 +72,54 @@ private slots:
void unicodeVersion();
};
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
void tst_QChar::operator_eqeq_int()
void tst_QChar::operator_eqeq_null()
{
{
const QChar ch = QLatin1Char(' ');
QVERIFY(ch != 0);
QVERIFY(!(ch == 0));
#define CHECK(NUL) \
do { \
QVERIFY(!(ch == NUL)); \
QVERIFY( ch != NUL ); \
QVERIFY(!(ch < NUL)); \
QVERIFY( ch > NUL ); \
QVERIFY(!(ch <= NUL)); \
QVERIFY( ch >= NUL ); \
QVERIFY(!(NUL == ch )); \
QVERIFY( NUL != ch ); \
QVERIFY( NUL < ch ); \
QVERIFY(!(NUL > ch )); \
QVERIFY( NUL <= ch ); \
QVERIFY(!(NUL >= ch )); \
} while (0)
QVERIFY(ch == 0x20);
QVERIFY(!(ch != 0x20));
QVERIFY(0x20 == ch);
QVERIFY(!(0x20 != ch));
CHECK(0);
CHECK('\0');
#undef CHECK
}
{
const QChar ch = QLatin1Char('\0');
QVERIFY(ch == 0);
QVERIFY(!(ch != 0));
#define CHECK(NUL) \
do { \
QVERIFY( ch == NUL ); \
QVERIFY(!(ch != NUL)); \
QVERIFY(!(ch < NUL)); \
QVERIFY(!(ch > NUL)); \
QVERIFY( ch <= NUL ); \
QVERIFY( ch >= NUL ); \
QVERIFY( NUL == ch ); \
QVERIFY(!(NUL != ch )); \
QVERIFY(!(NUL < ch )); \
QVERIFY(!(NUL > ch )); \
QVERIFY( NUL <= ch ); \
QVERIFY( NUL >= ch ); \
} while (0)
QVERIFY(ch != 0x20);
QVERIFY(!(ch == 0x20));
QVERIFY(0x20 != ch);
QVERIFY(!(0x20 == ch));
CHECK(0);
CHECK('\0');
#undef CHECK
}
}
QT_WARNING_POP
void tst_QChar::operators_data()
{
QTest::addColumn<QChar>("lhs");