Q*Ordering: supply is_{lt,gt,n,}eq

std::is_eq etc work fine on our Q*Ordering types when C++20 is
available. But in C++17 mode, they're absent.

Plug the hole by providing them for our own types as hidden friends,
so that users can use unqualified calls to transparently support both
std::*ordering and Q*Ordering types, just like with comparison to
literal zero.

For some reason, we running here into
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903, even though this
wasn't seen in other commits of the chain that use comparisons to
literal zero. Suppress the warning. Then at least is_eq etc provide a
safe fall-back for compilers and users affected by this bogus warning.

Fixes: QTBUG-119100
Change-Id: Ie8519c92363401a0c9c8efba6eb0b6e030a8e235
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2023-11-13 18:48:32 +01:00
parent d61cee0ed8
commit 67072a70af
3 changed files with 192 additions and 0 deletions

View File

@ -152,6 +152,17 @@ private:
: m_order(static_cast<QtPrivate::CompareUnderlyingType>(order)) : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
{} {}
QT_WARNING_PUSH
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
friend constexpr bool is_eq (QPartialOrdering o) noexcept { return o == 0; }
friend constexpr bool is_neq (QPartialOrdering o) noexcept { return o != 0; }
friend constexpr bool is_lt (QPartialOrdering o) noexcept { return o < 0; }
friend constexpr bool is_lteq(QPartialOrdering o) noexcept { return o <= 0; }
friend constexpr bool is_gt (QPartialOrdering o) noexcept { return o > 0; }
friend constexpr bool is_gteq(QPartialOrdering o) noexcept { return o >= 0; }
QT_WARNING_POP
// instead of the exposition only is_ordered member in [cmp.partialord], // instead of the exposition only is_ordered member in [cmp.partialord],
// use a private function // use a private function
constexpr bool isOrdered() const noexcept constexpr bool isOrdered() const noexcept
@ -309,6 +320,17 @@ private:
: m_order(static_cast<QtPrivate::CompareUnderlyingType>(order)) : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
{} {}
QT_WARNING_PUSH
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
friend constexpr bool is_eq (QWeakOrdering o) noexcept { return o == 0; }
friend constexpr bool is_neq (QWeakOrdering o) noexcept { return o != 0; }
friend constexpr bool is_lt (QWeakOrdering o) noexcept { return o < 0; }
friend constexpr bool is_lteq(QWeakOrdering o) noexcept { return o <= 0; }
friend constexpr bool is_gt (QWeakOrdering o) noexcept { return o > 0; }
friend constexpr bool is_gteq(QWeakOrdering o) noexcept { return o >= 0; }
QT_WARNING_POP
QtPrivate::CompareUnderlyingType m_order; QtPrivate::CompareUnderlyingType m_order;
}; };
@ -478,6 +500,17 @@ public:
: m_order(static_cast<QtPrivate::CompareUnderlyingType>(order)) : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
{} {}
QT_WARNING_PUSH
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
friend constexpr bool is_eq (QStrongOrdering o) noexcept { return o == 0; }
friend constexpr bool is_neq (QStrongOrdering o) noexcept { return o != 0; }
friend constexpr bool is_lt (QStrongOrdering o) noexcept { return o < 0; }
friend constexpr bool is_lteq(QStrongOrdering o) noexcept { return o <= 0; }
friend constexpr bool is_gt (QStrongOrdering o) noexcept { return o > 0; }
friend constexpr bool is_gteq(QStrongOrdering o) noexcept { return o >= 0; }
QT_WARNING_POP
QtPrivate::CompareUnderlyingType m_order; QtPrivate::CompareUnderlyingType m_order;
}; };

View File

@ -223,6 +223,30 @@
\fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QStrongOrdering rhs) \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QStrongOrdering rhs)
*/ */
/*!
\fn QStrongOrdering::is_eq (QStrongOrdering o)
\fn QStrongOrdering::is_neq (QStrongOrdering o)
\fn QStrongOrdering::is_lt (QStrongOrdering o)
\fn QStrongOrdering::is_lteq(QStrongOrdering o)
\fn QStrongOrdering::is_gt (QStrongOrdering o)
\fn QStrongOrdering::is_gteq(QStrongOrdering o)
//! [is_eq_table]
Converts \a o into the result of one of the six relational operators:
\table
\header \li Function \li Operation
\row \li \c{is_eq} \li \a o \c{== 0}
\row \li \c{is_neq} \li \a o \c{!= 0}
\row \li \c{is_lt} \li \a o \c{< 0}
\row \li \c{is_lteq} \li \a o \c{<= 0}
\row \li \c{is_gt} \li \a o \c{> 0}
\row \li \c{is_gteq} \li \a o \c{>= 0}
\endtable
//! [is_eq_table]
These functions are provided for compatibility with \c{std::strong_ordering}.
*/
/*! /*!
\variable QStrongOrdering::Less \variable QStrongOrdering::Less
@ -366,6 +390,19 @@
\fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QWeakOrdering rhs) \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QWeakOrdering rhs)
*/ */
/*!
\fn QWeakOrdering::is_eq (QWeakOrdering o)
\fn QWeakOrdering::is_neq (QWeakOrdering o)
\fn QWeakOrdering::is_lt (QWeakOrdering o)
\fn QWeakOrdering::is_lteq(QWeakOrdering o)
\fn QWeakOrdering::is_gt (QWeakOrdering o)
\fn QWeakOrdering::is_gteq(QWeakOrdering o)
\include qcompare.qdoc is_eq_table
These functions are provided for compatibility with \c{std::weak_ordering}.
*/
/*! /*!
\variable QWeakOrdering::Less \variable QWeakOrdering::Less
@ -499,6 +536,19 @@
\fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs) \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
*/ */
/*!
\fn QPartialOrdering::is_eq (QPartialOrdering o)
\fn QPartialOrdering::is_neq (QPartialOrdering o)
\fn QPartialOrdering::is_lt (QPartialOrdering o)
\fn QPartialOrdering::is_lteq(QPartialOrdering o)
\fn QPartialOrdering::is_gt (QPartialOrdering o)
\fn QPartialOrdering::is_gteq(QPartialOrdering o)
\include qcompare.qdoc is_eq_table
These functions are provided for compatibility with \c{std::partial_ordering}.
*/
/*! /*!
\variable QPartialOrdering::Less \variable QPartialOrdering::Less

View File

@ -16,6 +16,7 @@ private slots:
void weakOrdering(); void weakOrdering();
void strongOrdering(); void strongOrdering();
void conversions(); void conversions();
void is_eq_overloads();
}; };
void tst_QCompare::partialOrdering() void tst_QCompare::partialOrdering()
@ -40,6 +41,12 @@ void tst_QCompare::partialOrdering()
static_assert(QPartialOrdering::Greater != QPartialOrdering::Equivalent); static_assert(QPartialOrdering::Greater != QPartialOrdering::Equivalent);
static_assert(QPartialOrdering::Greater == QPartialOrdering::Greater); static_assert(QPartialOrdering::Greater == QPartialOrdering::Greater);
static_assert(!is_eq (QPartialOrdering::Unordered));
static_assert(!is_neq (QPartialOrdering::Unordered));
static_assert(!is_lt (QPartialOrdering::Unordered));
static_assert(!is_lteq(QPartialOrdering::Unordered));
static_assert(!is_gt (QPartialOrdering::Unordered));
static_assert(!is_gteq(QPartialOrdering::Unordered));
static_assert(!(QPartialOrdering::Unordered == 0)); static_assert(!(QPartialOrdering::Unordered == 0));
static_assert(!(QPartialOrdering::Unordered != 0)); static_assert(!(QPartialOrdering::Unordered != 0));
@ -56,6 +63,13 @@ void tst_QCompare::partialOrdering()
static_assert(!(0 >= QPartialOrdering::Unordered)); static_assert(!(0 >= QPartialOrdering::Unordered));
static_assert(!is_eq (QPartialOrdering::Less));
static_assert( is_neq (QPartialOrdering::Less));
static_assert( is_lt (QPartialOrdering::Less));
static_assert( is_lteq(QPartialOrdering::Less));
static_assert(!is_gt (QPartialOrdering::Less));
static_assert(!is_gteq(QPartialOrdering::Less));
static_assert(!(QPartialOrdering::Less == 0)); static_assert(!(QPartialOrdering::Less == 0));
static_assert( (QPartialOrdering::Less != 0)); static_assert( (QPartialOrdering::Less != 0));
static_assert( (QPartialOrdering::Less < 0)); static_assert( (QPartialOrdering::Less < 0));
@ -71,6 +85,13 @@ void tst_QCompare::partialOrdering()
static_assert( (0 >= QPartialOrdering::Less)); static_assert( (0 >= QPartialOrdering::Less));
static_assert( is_eq (QPartialOrdering::Equivalent));
static_assert(!is_neq (QPartialOrdering::Equivalent));
static_assert(!is_lt (QPartialOrdering::Equivalent));
static_assert( is_lteq(QPartialOrdering::Equivalent));
static_assert(!is_gt (QPartialOrdering::Equivalent));
static_assert( is_gteq(QPartialOrdering::Equivalent));
static_assert( (QPartialOrdering::Equivalent == 0)); static_assert( (QPartialOrdering::Equivalent == 0));
static_assert(!(QPartialOrdering::Equivalent != 0)); static_assert(!(QPartialOrdering::Equivalent != 0));
static_assert(!(QPartialOrdering::Equivalent < 0)); static_assert(!(QPartialOrdering::Equivalent < 0));
@ -86,6 +107,13 @@ void tst_QCompare::partialOrdering()
static_assert( (0 >= QPartialOrdering::Equivalent)); static_assert( (0 >= QPartialOrdering::Equivalent));
static_assert(!is_eq (QPartialOrdering::Greater));
static_assert( is_neq (QPartialOrdering::Greater));
static_assert(!is_lt (QPartialOrdering::Greater));
static_assert(!is_lteq(QPartialOrdering::Greater));
static_assert( is_gt (QPartialOrdering::Greater));
static_assert( is_gteq(QPartialOrdering::Greater));
static_assert(!(QPartialOrdering::Greater == 0)); static_assert(!(QPartialOrdering::Greater == 0));
static_assert( (QPartialOrdering::Greater != 0)); static_assert( (QPartialOrdering::Greater != 0));
static_assert(!(QPartialOrdering::Greater < 0)); static_assert(!(QPartialOrdering::Greater < 0));
@ -115,6 +143,13 @@ void tst_QCompare::weakOrdering()
static_assert(QWeakOrdering::Greater != QWeakOrdering::Equivalent); static_assert(QWeakOrdering::Greater != QWeakOrdering::Equivalent);
static_assert(QWeakOrdering::Greater == QWeakOrdering::Greater); static_assert(QWeakOrdering::Greater == QWeakOrdering::Greater);
static_assert(!is_eq (QWeakOrdering::Less));
static_assert( is_neq (QWeakOrdering::Less));
static_assert( is_lt (QWeakOrdering::Less));
static_assert( is_lteq(QWeakOrdering::Less));
static_assert(!is_gt (QWeakOrdering::Less));
static_assert(!is_gteq(QWeakOrdering::Less));
static_assert(!(QWeakOrdering::Less == 0)); static_assert(!(QWeakOrdering::Less == 0));
static_assert( (QWeakOrdering::Less != 0)); static_assert( (QWeakOrdering::Less != 0));
static_assert( (QWeakOrdering::Less < 0)); static_assert( (QWeakOrdering::Less < 0));
@ -129,6 +164,14 @@ void tst_QCompare::weakOrdering()
static_assert( (0 > QWeakOrdering::Less)); static_assert( (0 > QWeakOrdering::Less));
static_assert( (0 >= QWeakOrdering::Less)); static_assert( (0 >= QWeakOrdering::Less));
static_assert( is_eq (QWeakOrdering::Equivalent));
static_assert(!is_neq (QWeakOrdering::Equivalent));
static_assert(!is_lt (QWeakOrdering::Equivalent));
static_assert( is_lteq(QWeakOrdering::Equivalent));
static_assert(!is_gt (QWeakOrdering::Equivalent));
static_assert( is_gteq(QWeakOrdering::Equivalent));
static_assert( (QWeakOrdering::Equivalent == 0)); static_assert( (QWeakOrdering::Equivalent == 0));
static_assert(!(QWeakOrdering::Equivalent != 0)); static_assert(!(QWeakOrdering::Equivalent != 0));
static_assert(!(QWeakOrdering::Equivalent < 0)); static_assert(!(QWeakOrdering::Equivalent < 0));
@ -143,6 +186,14 @@ void tst_QCompare::weakOrdering()
static_assert(!(0 > QWeakOrdering::Equivalent)); static_assert(!(0 > QWeakOrdering::Equivalent));
static_assert( (0 >= QWeakOrdering::Equivalent)); static_assert( (0 >= QWeakOrdering::Equivalent));
static_assert(!is_eq (QWeakOrdering::Greater));
static_assert( is_neq (QWeakOrdering::Greater));
static_assert(!is_lt (QWeakOrdering::Greater));
static_assert(!is_lteq(QWeakOrdering::Greater));
static_assert( is_gt (QWeakOrdering::Greater));
static_assert( is_gteq(QWeakOrdering::Greater));
static_assert(!(QWeakOrdering::Greater == 0)); static_assert(!(QWeakOrdering::Greater == 0));
static_assert( (QWeakOrdering::Greater != 0)); static_assert( (QWeakOrdering::Greater != 0));
static_assert(!(QWeakOrdering::Greater < 0)); static_assert(!(QWeakOrdering::Greater < 0));
@ -180,6 +231,13 @@ void tst_QCompare::strongOrdering()
static_assert(QStrongOrdering::Greater != QStrongOrdering::Equivalent); static_assert(QStrongOrdering::Greater != QStrongOrdering::Equivalent);
static_assert(QStrongOrdering::Greater == QStrongOrdering::Greater); static_assert(QStrongOrdering::Greater == QStrongOrdering::Greater);
static_assert(!is_eq (QStrongOrdering::Less));
static_assert( is_neq (QStrongOrdering::Less));
static_assert( is_lt (QStrongOrdering::Less));
static_assert( is_lteq(QStrongOrdering::Less));
static_assert(!is_gt (QStrongOrdering::Less));
static_assert(!is_gteq(QStrongOrdering::Less));
static_assert(!(QStrongOrdering::Less == 0)); static_assert(!(QStrongOrdering::Less == 0));
static_assert( (QStrongOrdering::Less != 0)); static_assert( (QStrongOrdering::Less != 0));
static_assert( (QStrongOrdering::Less < 0)); static_assert( (QStrongOrdering::Less < 0));
@ -194,6 +252,14 @@ void tst_QCompare::strongOrdering()
static_assert( (0 > QStrongOrdering::Less)); static_assert( (0 > QStrongOrdering::Less));
static_assert( (0 >= QStrongOrdering::Less)); static_assert( (0 >= QStrongOrdering::Less));
static_assert( is_eq (QStrongOrdering::Equal));
static_assert(!is_neq (QStrongOrdering::Equal));
static_assert(!is_lt (QStrongOrdering::Equal));
static_assert( is_lteq(QStrongOrdering::Equal));
static_assert(!is_gt (QStrongOrdering::Equal));
static_assert( is_gteq(QStrongOrdering::Equal));
static_assert( (QStrongOrdering::Equal == 0)); static_assert( (QStrongOrdering::Equal == 0));
static_assert(!(QStrongOrdering::Equal != 0)); static_assert(!(QStrongOrdering::Equal != 0));
static_assert(!(QStrongOrdering::Equal < 0)); static_assert(!(QStrongOrdering::Equal < 0));
@ -208,6 +274,14 @@ void tst_QCompare::strongOrdering()
static_assert(!(0 > QStrongOrdering::Equal)); static_assert(!(0 > QStrongOrdering::Equal));
static_assert( (0 >= QStrongOrdering::Equal)); static_assert( (0 >= QStrongOrdering::Equal));
static_assert( is_eq (QStrongOrdering::Equivalent));
static_assert(!is_neq (QStrongOrdering::Equivalent));
static_assert(!is_lt (QStrongOrdering::Equivalent));
static_assert( is_lteq(QStrongOrdering::Equivalent));
static_assert(!is_gt (QStrongOrdering::Equivalent));
static_assert( is_gteq(QStrongOrdering::Equivalent));
static_assert( (QStrongOrdering::Equivalent == 0)); static_assert( (QStrongOrdering::Equivalent == 0));
static_assert(!(QStrongOrdering::Equivalent != 0)); static_assert(!(QStrongOrdering::Equivalent != 0));
static_assert(!(QStrongOrdering::Equivalent < 0)); static_assert(!(QStrongOrdering::Equivalent < 0));
@ -222,6 +296,14 @@ void tst_QCompare::strongOrdering()
static_assert(!(0 > QStrongOrdering::Equivalent)); static_assert(!(0 > QStrongOrdering::Equivalent));
static_assert( (0 >= QStrongOrdering::Equivalent)); static_assert( (0 >= QStrongOrdering::Equivalent));
static_assert(!is_eq (QStrongOrdering::Greater));
static_assert( is_neq (QStrongOrdering::Greater));
static_assert(!is_lt (QStrongOrdering::Greater));
static_assert(!is_lteq(QStrongOrdering::Greater));
static_assert( is_gt (QStrongOrdering::Greater));
static_assert( is_gteq(QStrongOrdering::Greater));
static_assert(!(QStrongOrdering::Greater == 0)); static_assert(!(QStrongOrdering::Greater == 0));
static_assert( (QStrongOrdering::Greater != 0)); static_assert( (QStrongOrdering::Greater != 0));
static_assert(!(QStrongOrdering::Greater < 0)); static_assert(!(QStrongOrdering::Greater < 0));
@ -366,5 +448,32 @@ void tst_QCompare::conversions()
} }
void tst_QCompare::is_eq_overloads()
{
#ifndef __cpp_lib_three_way_comparison
QSKIP("This test requires C++20 three-way-comparison support enabled in the stdlib.");
#else
constexpr auto u = std::partial_ordering::unordered;
constexpr auto l = std::weak_ordering::less;
constexpr auto g = std::strong_ordering::greater;
constexpr auto e = std::weak_ordering::equivalent;
constexpr auto s = std::strong_ordering::equal;
// This is a compile-time check that unqualified name lookup of
// std::is_eq-like functions isn't ambiguous, so we can recommend it to our
// users for minimizing porting on the way to C++20.
// The goal is to check each std::ordering and each is_eq function at least
// once, not to test all combinations (we're not the stdlib test suite here).
QVERIFY(is_eq(s));
QVERIFY(is_neq(u));
QVERIFY(is_lt(l));
QVERIFY(is_gt(g));
QVERIFY(is_lteq(e));
QVERIFY(is_gteq(s));
#endif // __cpp_lib_three_way_comparison
}
QTEST_MAIN(tst_QCompare) QTEST_MAIN(tst_QCompare)
#include "tst_qcompare.moc" #include "tst_qcompare.moc"