Update Qt::compareThreeWay(Qt::totally_ordered_wrapper) overloads to take compatible pointer types

Unlike the old Qt::compareThreeWay() overload for raw pointers, the new
overloads for the Qt::totally_ordered_wrapper didn't allow to compare
wrappers of different (but compatible) pointer types (base vs derived).

This patch fixes it.

Ideally the constraints on operators in Qt::totally_ordered_wrapper
should use std::common_type_t, but we hit a bug in VxWorks that
prevents us from using it, so simply demand that the types are
convertible pointers. For now that should be enough, considering
that Qt::totally_ordered_wrapper only expects pointers as wrapped
types.

Found in API Review.

Change-Id: I9f7184468bea3e1f2944ca5347f0b79eded2f4d3
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit d73bdec05101b34745156c8cd4ea571f1223ad32)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Ivan Solovev 2024-05-29 14:02:58 +02:00 committed by Qt Cherry-pick Bot
parent e37c0a33a4
commit 814dc9715b
3 changed files with 44 additions and 20 deletions

View File

@ -1313,7 +1313,7 @@ CHECK(strong, equivalent);
*/
/*!
\fn template <typename T> Qt::compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, Qt::totally_ordered_wrapper<T*> rhs)
\fn template <typename T, typename U, Qt::if_compatible_pointers<T, U> = true> Qt::compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, Qt::totally_ordered_wrapper<U*> rhs)
\since 6.8
\relates <QtCompare>
\overload
@ -1323,12 +1323,15 @@ CHECK(strong, equivalent);
\l {https://en.cppreference.com/w/cpp/language/operator_comparison#Pointer_total_order}
{strict total order over pointers} when doing the comparison.
\note This function participates in overload resolution if \c T and \c U
are the same type, or base and derived types.
Returns an instance of \l Qt::strong_ordering that represents the relation
between \a lhs and \a rhs.
*/
/*!
\fn template <typename T> Qt::compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, T *rhs)
\fn template <typename T, typename U, Qt::if_compatible_pointers<T, U> = true> Qt::compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, U *rhs)
\since 6.8
\relates <QtCompare>
\overload
@ -1338,12 +1341,15 @@ CHECK(strong, equivalent);
\l {https://en.cppreference.com/w/cpp/language/operator_comparison#Pointer_total_order}
{strict total order over pointers} when doing the comparison.
\note This function participates in overload resolution if \c T and \c U
are the same type, or base and derived types.
Returns an instance of \l Qt::strong_ordering that represents the relation
between \a lhs and \a rhs.
*/
/*!
\fn template <typename T> Qt::compareThreeWay(T *lhs, Qt::totally_ordered_wrapper<T*> rhs)
\fn template <typename T, typename U, Qt::if_compatible_pointers<T, U> = true> Qt::compareThreeWay(U *lhs, Qt::totally_ordered_wrapper<T*> rhs)
\since 6.8
\relates <QtCompare>
\overload
@ -1353,6 +1359,9 @@ CHECK(strong, equivalent);
\l {https://en.cppreference.com/w/cpp/language/operator_comparison#Pointer_total_order}
{strict total order over pointers} when doing the comparison.
\note This function participates in overload resolution if \c T and \c U
are the same type, or base and derived types.
Returns an instance of \l Qt::strong_ordering that represents the relation
between \a lhs and \a rhs.
*/

View File

@ -657,24 +657,37 @@ public:
explicit constexpr operator bool() const noexcept { return get(); }
private:
// TODO: Replace the constraints with std::common_type_t<P, U> when
// a bug in VxWorks is fixed!
template <typename T, typename U>
using if_compatible_types =
std::enable_if_t<std::conjunction_v<std::is_pointer<T>,
std::is_pointer<U>,
std::disjunction<std::is_convertible<T, U>,
std::is_convertible<U, T>>>,
bool>;
#define MAKE_RELOP(Ret, op, Op) \
friend constexpr Ret operator op (const totally_ordered_wrapper &lhs, const totally_ordered_wrapper &rhs) noexcept \
{ return std:: Op {}(lhs.ptr, rhs.ptr); } \
friend constexpr Ret operator op (const totally_ordered_wrapper &lhs, const P &rhs) noexcept \
template <typename U = P, if_compatible_types<P, U> = true> \
friend constexpr Ret operator op (const totally_ordered_wrapper<P> &lhs, const totally_ordered_wrapper<U> &rhs) noexcept \
{ return std:: Op {}(lhs.ptr, rhs.get()); } \
template <typename U = P, if_compatible_types<P, U> = true> \
friend constexpr Ret operator op (const totally_ordered_wrapper<P> &lhs, const U &rhs) noexcept \
{ return std:: Op {}(lhs.ptr, rhs ); } \
friend constexpr Ret operator op (const P &lhs, const totally_ordered_wrapper &rhs) noexcept \
template <typename U = P, if_compatible_types<P, U> = true> \
friend constexpr Ret operator op (const U &lhs, const totally_ordered_wrapper<P> &rhs) noexcept \
{ return std:: Op {}(lhs, rhs.ptr); } \
friend constexpr Ret operator op (const totally_ordered_wrapper &lhs, std::nullptr_t) noexcept \
{ return std:: Op {}(lhs.ptr, P(nullptr)); } \
friend constexpr Ret operator op (std::nullptr_t, const totally_ordered_wrapper &rhs) noexcept \
{ return std:: Op {}(P(nullptr), rhs.ptr); } \
/* end */
MAKE_RELOP(bool, ==, equal_to<P>)
MAKE_RELOP(bool, !=, not_equal_to<P>)
MAKE_RELOP(bool, < , less<P>)
MAKE_RELOP(bool, <=, less_equal<P>)
MAKE_RELOP(bool, > , greater<P>)
MAKE_RELOP(bool, >=, greater_equal<P>)
MAKE_RELOP(bool, ==, equal_to<>)
MAKE_RELOP(bool, !=, not_equal_to<>)
MAKE_RELOP(bool, < , less<>)
MAKE_RELOP(bool, <=, less_equal<>)
MAKE_RELOP(bool, > , greater<>)
MAKE_RELOP(bool, >=, greater_equal<>)
#ifdef __cpp_lib_three_way_comparison
MAKE_RELOP(auto, <=>, compare_three_way)
#endif
@ -687,23 +700,23 @@ private:
{ return qHash(key.ptr, seed); }
};
template <typename T>
template <typename T, typename U, if_compatible_pointers<T, U> = true>
constexpr Qt::strong_ordering
compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, Qt::totally_ordered_wrapper<T*> rhs) noexcept
compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, Qt::totally_ordered_wrapper<U*> rhs) noexcept
{
return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
}
template <typename T>
template <typename T, typename U, if_compatible_pointers<T, U> = true>
constexpr Qt::strong_ordering
compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, T *rhs) noexcept
compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, U *rhs) noexcept
{
return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
}
template <typename T>
template <typename T, typename U, if_compatible_pointers<T, U> = true>
constexpr Qt::strong_ordering
compareThreeWay(T *lhs, Qt::totally_ordered_wrapper<T*> rhs) noexcept
compareThreeWay(U *lhs, Qt::totally_ordered_wrapper<T*> rhs) noexcept
{
return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
}

View File

@ -610,8 +610,10 @@ QT_WARNING_POP
QCOMPARE_EQ(Qt::compareThreeWay(arr.data(), a0), Qt::strong_ordering::equivalent);
auto bWrapper = Qt::totally_ordered_wrapper(b.get());
auto dWrapper = Qt::totally_ordered_wrapper<Base*>(d.get());
auto dWrapper = Qt::totally_ordered_wrapper(d.get());
QCOMPARE_NE(Qt::compareThreeWay(bWrapper, dWrapper), Qt::strong_ordering::equivalent);
QCOMPARE_NE(Qt::compareThreeWay(bWrapper, d.get()), Qt::strong_ordering::equivalent);
QCOMPARE_NE(Qt::compareThreeWay(b.get(), dWrapper), Qt::strong_ordering::equivalent);
QCOMPARE_EQ(Qt::compareThreeWay(bWrapper, nullptr), Qt::strong_ordering::greater);
QCOMPARE_EQ(Qt::compareThreeWay(nullptr, dWrapper), Qt::strong_ordering::less);