Long live Q_DECLARE_ORDERED
This is a version of the comparison helper macro for the cases where the ordering strength depends on the template arguments (think std::pair<double, int> vs std::pair<int, int>). This patch also adds the _LITERAL_TYPE and _NON_NOEXCEPT overloads of the macros that generate the constexpr and noexpect(false) relational operators respectively. Done-with: Ivan Solovev <ivan.solovev@qt.io> Task-number: QTBUG-127095 Change-Id: I368cf2ff385213be7d2c7477a8346e83ce841b91 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
a8ca9c418f
commit
5d8f2b7cd2
@ -1225,6 +1225,60 @@ CHECK(strong, equivalent);
|
||||
Starting from Qt 6.9, \c Attributes becomes a variable argument.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\internal
|
||||
\macro Q_DECLARE_ORDERED(Type)
|
||||
\macro Q_DECLARE_ORDERED(LeftType, RightType)
|
||||
\macro Q_DECLARE_ORDERED(LeftType, RightType, Attributes...)
|
||||
\macro Q_DECLARE_ORDERED_LITERAL_TYPE(Type)
|
||||
\macro Q_DECLARE_ORDERED_LITERAL_TYPE(LeftType, RightType)
|
||||
\macro Q_DECLARE_ORDERED_LITERAL_TYPE(LeftType, RightType, Attributes...)
|
||||
\macro Q_DECLARE_ORDERED_NON_NOEXCEPT(Type)
|
||||
\macro Q_DECLARE_ORDERED_NON_NOEXCEPT(LeftType, RightType)
|
||||
\macro Q_DECLARE_ORDERED_NON_NOEXCEPT(LeftType, RightType, Attributes...)
|
||||
\since 6.9
|
||||
\relates <QtCompare>
|
||||
|
||||
These macros behave similarly to the
|
||||
\c {Q_DECLARE_(PARTIALLY,WEAKLY,STRONGLY)_ORDERED} overloads, but represent
|
||||
any one of those three, using \c auto return type.
|
||||
|
||||
This is what you typically would use for template classes where
|
||||
the strength of the ordering depends on the template arguments.
|
||||
For example, if one of the template arguments is a floating-point
|
||||
type, the ordering would be \l {Qt::partial_ordering}, if they all
|
||||
are integral - \l {Qt::strong_ordering}.
|
||||
|
||||
\note It is better to use one of the explicit-strength macros in general, to
|
||||
communicate intent. Use these macros only when the stength actually does vary
|
||||
with template arguments.
|
||||
|
||||
The (in)equality operators are implemented in terms of a helper function
|
||||
\c {comparesEqual()}. The other relational operators are implemented in
|
||||
terms of a helper function \c {compareThreeWay()}.
|
||||
The \c {compareThreeWay()} function \e must return an object of an ordering
|
||||
type. It's the user's responsibility to declare and define both helper
|
||||
functions.
|
||||
|
||||
The \c {*_LITERAL_TYPE} overloads are used to generate \c constexpr
|
||||
operators. This means that the helper \c {comparesEqual()} and
|
||||
\c {compareThreeWay()} functions must also be \c constexpr.
|
||||
|
||||
See \l {Q_DECLARE_PARTIALLY_ORDERED} for usage examples.
|
||||
|
||||
By default, the generated operators are \c {noexcept}.
|
||||
Use the \c {*_NON_NOEXCEPT} overloads if the relational operators cannot be
|
||||
\c {noexcept}.
|
||||
|
||||
The three-argument versions of the macros allow specification of C++
|
||||
attributes to add before every generated relational operator.
|
||||
See \l {Q_DECLARE_EQUALITY_COMPARABLE(LeftType, RightType, Attributes...)}
|
||||
for more details and usage examples.
|
||||
|
||||
\sa Q_DECLARE_PARTIALLY_ORDERED, Q_DECLARE_WEAKLY_ORDERED,
|
||||
Q_DECLARE_STRONGLY_ORDERED, Q_DECLARE_EQUALITY_COMPARABLE
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename LeftInt, typename RightInt, Qt::if_integral<LeftInt> = true, Qt::if_integral<RightInt> = true> auto Qt::compareThreeWay(LeftInt lhs, RightInt rhs)
|
||||
\since 6.7
|
||||
|
@ -208,6 +208,15 @@ orderingFlagsFor(T t) noexcept
|
||||
return compareThreeWay(lhs, rhs); \
|
||||
}
|
||||
|
||||
#define QT_DECLARE_3WAY_HELPER_AUTO(LeftType, RightType, Constexpr, Noexcept, ...) \
|
||||
__VA_ARGS__ \
|
||||
friend Constexpr auto \
|
||||
operator<=>(LeftType const &lhs, RightType const &rhs) Noexcept \
|
||||
{ \
|
||||
QT_COMPARISON_NOEXCEPT_CHECK(Noexcept, compareThreeWay);\
|
||||
return QtOrderingPrivate::to_std(compareThreeWay(lhs, rhs)); \
|
||||
}
|
||||
|
||||
#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingType, LeftType, RightType, Constexpr, \
|
||||
Noexcept, ...) \
|
||||
QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Noexcept, __VA_ARGS__) \
|
||||
@ -253,6 +262,15 @@ orderingFlagsFor(T t) noexcept
|
||||
return QtOrderingPrivate::reversed(r); \
|
||||
}
|
||||
|
||||
#define QT_DECLARE_REVERSED_3WAY_HELPER_AUTO(LeftType, RightType, Constexpr, Noexcept, ...) \
|
||||
__VA_ARGS__ \
|
||||
friend Constexpr auto \
|
||||
operator<=>(RightType const &lhs, LeftType const &rhs) Noexcept \
|
||||
{ \
|
||||
const auto r = compareThreeWay(rhs, lhs); \
|
||||
return QtOrderingPrivate::to_std(QtOrderingPrivate::reversed(r)); \
|
||||
}
|
||||
|
||||
#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
|
||||
Constexpr, Noexcept, ...) \
|
||||
QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, \
|
||||
@ -314,6 +332,10 @@ orderingFlagsFor(T t) noexcept
|
||||
friend Constexpr bool operator>=(LeftType const &lhs, RightType const &rhs) Noexcept \
|
||||
{ return is_gteq(compareThreeWay(lhs, rhs)); }
|
||||
|
||||
#define QT_DECLARE_ORDERING_HELPER_AUTO(LeftType, RightType, Constexpr, Noexcept, ...) \
|
||||
QT_DECLARE_ORDERING_HELPER_TEMPLATE(auto, LeftType, RightType, Constexpr, Noexcept, \
|
||||
__VA_ARGS__)
|
||||
|
||||
#define QT_DECLARE_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Noexcept, ...) \
|
||||
QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, Constexpr, \
|
||||
Noexcept, __VA_ARGS__)
|
||||
@ -348,6 +370,10 @@ orderingFlagsFor(T t) noexcept
|
||||
friend Constexpr bool operator>=(RightType const &lhs, LeftType const &rhs) Noexcept \
|
||||
{ return is_lteq(compareThreeWay(rhs, lhs)); }
|
||||
|
||||
#define QT_DECLARE_REVERSED_ORDERING_HELPER_AUTO(LeftType, RightType, Constexpr, Noexcept, ...) \
|
||||
QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(auto, LeftType, RightType, Constexpr, Noexcept, \
|
||||
__VA_ARGS__)
|
||||
|
||||
#define QT_DECLARE_REVERSED_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Noexcept, ...) \
|
||||
QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, \
|
||||
Constexpr, Noexcept, __VA_ARGS__)
|
||||
@ -468,6 +494,96 @@ orderingFlagsFor(T t) noexcept
|
||||
#define Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(...) \
|
||||
QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT, __VA_ARGS__)
|
||||
|
||||
// Ordering operators that automatically deduce the strength:
|
||||
#define QT_DECLARE_ORDERED_1(Type) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_HELPER(AUTO, Type, Type, /* non-constexpr */, noexcept(true), \
|
||||
/* no attributes */)
|
||||
|
||||
#define QT_DECLARE_ORDERED_2(LeftType, RightType) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_HELPER(AUTO, LeftType, RightType, /* non-constexpr */, \
|
||||
noexcept(true), /* no attributes */) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(AUTO, LeftType, RightType, /* non-constexpr */, \
|
||||
noexcept(true), /* no attributes */)
|
||||
|
||||
#define QT_DECLARE_ORDERED_3(LeftType, RightType, ...) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_HELPER(AUTO, LeftType, RightType, /* non-constexpr */, \
|
||||
noexcept(true), __VA_ARGS__) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(AUTO, LeftType, RightType, /* non-constexpr */, \
|
||||
noexcept(true), __VA_ARGS__)
|
||||
|
||||
#define QT_DECLARE_ORDERED_4(...) QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_5(...) QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_6(...) QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_7(...) QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_8(...) QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_9(...) QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_3(__VA_ARGS__))
|
||||
|
||||
#define Q_DECLARE_ORDERED(...) QT_OVERLOADED_MACRO(QT_DECLARE_ORDERED, __VA_ARGS__)
|
||||
|
||||
#define QT_DECLARE_ORDERED_LITERAL_TYPE_1(Type) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_HELPER(AUTO, Type, Type, constexpr, noexcept(true), \
|
||||
/* no attributes */)
|
||||
|
||||
#define QT_DECLARE_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_HELPER(AUTO, LeftType, RightType, constexpr, \
|
||||
noexcept(true), /* no attributes */) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(AUTO, LeftType, RightType, constexpr, \
|
||||
noexcept(true), /* no attributes */)
|
||||
|
||||
#define QT_DECLARE_ORDERED_LITERAL_TYPE_3(LeftType, RightType, ...) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_HELPER(AUTO, LeftType, RightType, constexpr, \
|
||||
noexcept(true), __VA_ARGS__) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(AUTO, LeftType, RightType, constexpr, \
|
||||
noexcept(true), __VA_ARGS__)
|
||||
|
||||
#define QT_DECLARE_ORDERED_LITERAL_TYPE_4(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_LITERAL_TYPE_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_LITERAL_TYPE_5(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_LITERAL_TYPE_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_LITERAL_TYPE_6(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_LITERAL_TYPE_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_LITERAL_TYPE_7(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_LITERAL_TYPE_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_LITERAL_TYPE_8(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_LITERAL_TYPE_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_LITERAL_TYPE_9(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_LITERAL_TYPE_3(__VA_ARGS__))
|
||||
|
||||
#define Q_DECLARE_ORDERED_LITERAL_TYPE(...) \
|
||||
QT_OVERLOADED_MACRO(QT_DECLARE_ORDERED_LITERAL_TYPE, __VA_ARGS__)
|
||||
|
||||
#define QT_DECLARE_ORDERED_NON_NOEXCEPT_1(Type) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_HELPER(AUTO, Type, Type, /* non-constexpr */, noexcept(false), \
|
||||
/* no attributes */)
|
||||
|
||||
#define QT_DECLARE_ORDERED_NON_NOEXCEPT_2(LeftType, RightType) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_HELPER(AUTO, LeftType, RightType, /* non-constexpr */, \
|
||||
noexcept(false), /* no attributes */) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(AUTO, LeftType, RightType, /* non-constexpr */, \
|
||||
noexcept(false), /* no attributes */)
|
||||
|
||||
#define QT_DECLARE_ORDERED_NON_NOEXCEPT_3(LeftType, RightType, ...) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_HELPER(AUTO, LeftType, RightType, /* non-constexpr */, \
|
||||
noexcept(false), __VA_ARGS__) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(AUTO, LeftType, RightType, /* non-constexpr */, \
|
||||
noexcept(false), __VA_ARGS__)
|
||||
|
||||
#define QT_DECLARE_ORDERED_NON_NOEXCEPT_4(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_NON_NOEXCEPT_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_NON_NOEXCEPT_5(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_NON_NOEXCEPT_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_NON_NOEXCEPT_6(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_NON_NOEXCEPT_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_NON_NOEXCEPT_7(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_NON_NOEXCEPT_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_NON_NOEXCEPT_8(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_NON_NOEXCEPT_3(__VA_ARGS__))
|
||||
#define QT_DECLARE_ORDERED_NON_NOEXCEPT_9(...) \
|
||||
QT_VA_ARGS_EXPAND(QT_DECLARE_ORDERED_NON_NOEXCEPT_3(__VA_ARGS__))
|
||||
|
||||
#define Q_DECLARE_ORDERED_NON_NOEXCEPT(...) \
|
||||
QT_OVERLOADED_MACRO(QT_DECLARE_ORDERED_NON_NOEXCEPT, __VA_ARGS__)
|
||||
|
||||
// Partial ordering operators
|
||||
#define QT_DECLARE_PARTIALLY_ORDERED_1(Type) \
|
||||
QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, /* non-constexpr */, \
|
||||
|
@ -64,6 +64,8 @@ private Q_SLOTS:
|
||||
void compareWithAttributes();
|
||||
|
||||
void totallyOrderedWrapperBasics();
|
||||
|
||||
void compareAutoReturnType();
|
||||
};
|
||||
|
||||
#endif // TST_QCOMPAREHELPERS_H
|
||||
|
@ -22,6 +22,28 @@ private: \
|
||||
}; \
|
||||
/* END */
|
||||
|
||||
#define DECLARE_AUTO_TYPE(Name, Type, Constexpr, Noex, Suffix, ...) \
|
||||
class TemplatedAuto ## Name \
|
||||
{ \
|
||||
public: \
|
||||
Constexpr TemplatedAuto ## Name () {} \
|
||||
Constexpr TemplatedAuto ## Name (Type v) : val(v) {} \
|
||||
\
|
||||
private: \
|
||||
__VA_ARGS__ \
|
||||
friend Constexpr bool \
|
||||
comparesEqual(const TemplatedAuto ## Name &lhs, X rhs) noexcept(Noex) \
|
||||
{ return lhs.val == rhs; } \
|
||||
__VA_ARGS__ \
|
||||
friend Constexpr auto \
|
||||
compareThreeWay(const TemplatedAuto ## Name &lhs, X rhs) noexcept(Noex) \
|
||||
{ using Qt::compareThreeWay; return compareThreeWay(lhs.val, rhs); } \
|
||||
Q_DECLARE_ORDERED ## Suffix (TemplatedAuto ## Name, X, __VA_ARGS__) \
|
||||
\
|
||||
Type val = {}; \
|
||||
}; \
|
||||
/* END */
|
||||
|
||||
#define DECLARE_TYPES_FOR_N_ATTRS(N, ...) \
|
||||
DECLARE_TYPE(PartialConst ## N, PARTIALLY, Qt::partial_ordering, constexpr, \
|
||||
true, _LITERAL_TYPE, __VA_ARGS__) \
|
||||
@ -38,6 +60,9 @@ DECLARE_TYPE(StrongConst ## N, STRONGLY, Qt::strong_ordering, constexpr, true, \
|
||||
DECLARE_TYPE(Strong ## N, STRONGLY, Qt::strong_ordering, , true, , __VA_ARGS__) \
|
||||
DECLARE_TYPE(StrongNonNoex ## N, STRONGLY, Qt::strong_ordering, , false, \
|
||||
_NON_NOEXCEPT, __VA_ARGS__) \
|
||||
DECLARE_AUTO_TYPE(Def ## N, int, , true, , __VA_ARGS__) \
|
||||
DECLARE_AUTO_TYPE(Const ## N, int, constexpr, true, _LITERAL_TYPE, __VA_ARGS__) \
|
||||
DECLARE_AUTO_TYPE(NonNoex ## N, int, , false, _NON_NOEXCEPT, __VA_ARGS__) \
|
||||
/* END */
|
||||
|
||||
template <typename T>
|
||||
@ -91,6 +116,9 @@ void tst_QCompareHelpers::compareWithAttributes()
|
||||
COMPARE(TemplatedStrongConst ## N); \
|
||||
COMPARE(TemplatedStrong ## N); \
|
||||
COMPARE(TemplatedStrongNonNoex ## N); \
|
||||
COMPARE(TemplatedAutoDef ## N); \
|
||||
COMPARE(TemplatedAutoConst ## N); \
|
||||
COMPARE(TemplatedAutoNonNoex ## N); \
|
||||
/* END */
|
||||
|
||||
COMPARE_SET(1)
|
||||
@ -122,3 +150,51 @@ void tst_QCompareHelpers::totallyOrderedWrapperBasics()
|
||||
QCOMPARE_EQ(*intWrp, 20);
|
||||
QCOMPARE_EQ(val, 20);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class AutoComparisonTester
|
||||
{
|
||||
public:
|
||||
AutoComparisonTester(const T &v) : val(v) {}
|
||||
|
||||
private:
|
||||
friend bool
|
||||
comparesEqual(const AutoComparisonTester &lhs, const AutoComparisonTester &rhs) noexcept
|
||||
{ return lhs.val == rhs.val; }
|
||||
|
||||
friend auto
|
||||
compareThreeWay(const AutoComparisonTester &lhs, const AutoComparisonTester &rhs) noexcept
|
||||
{ using Qt::compareThreeWay; return compareThreeWay(lhs.val, rhs.val); }
|
||||
|
||||
Q_DECLARE_ORDERED(AutoComparisonTester)
|
||||
|
||||
T val;
|
||||
};
|
||||
|
||||
void tst_QCompareHelpers::compareAutoReturnType()
|
||||
{
|
||||
// strong
|
||||
{
|
||||
using StrongT = AutoComparisonTester<int>;
|
||||
static_assert(std::is_same_v<decltype(compareThreeWay(std::declval<const StrongT &>(),
|
||||
std::declval<const StrongT &>())),
|
||||
Qt::strong_ordering>);
|
||||
QTestPrivate::testAllComparisonOperatorsCompile<StrongT>();
|
||||
}
|
||||
// partial
|
||||
{
|
||||
using PartialT = AutoComparisonTester<float>;
|
||||
static_assert(std::is_same_v<decltype(compareThreeWay(std::declval<const PartialT &>(),
|
||||
std::declval<const PartialT &>())),
|
||||
Qt::partial_ordering>);
|
||||
QTestPrivate::testAllComparisonOperatorsCompile<PartialT>();
|
||||
}
|
||||
// weak
|
||||
{
|
||||
using WeakT = AutoComparisonTester<QDateTime>;
|
||||
static_assert(std::is_same_v<decltype(compareThreeWay(std::declval<const WeakT &>(),
|
||||
std::declval<const WeakT &>())),
|
||||
Qt::weak_ordering>);
|
||||
QTestPrivate::testAllComparisonOperatorsCompile<WeakT>();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user