[libc++] P2944R3: Constrained comparisions - variant (#141396)
This is a follow-up and depends on #139368 being merged first. Implements [P2944R3](https://wg21.link/P2944R3) partially, which adds constrained comparisons to `std::variant` Closes #136769 Depends on #139368 # References [variant.relops](https://wg21.link/variant.relops)
This commit is contained in:
@@ -59,7 +59,7 @@
|
||||
"`P2248R8 <https://wg21.link/P2248R8>`__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","",""
|
||||
"`P2810R4 <https://wg21.link/P2810R4>`__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","",""
|
||||
"`P1068R11 <https://wg21.link/P1068R11>`__","Vector API for random number generation","2024-03 (Tokyo)","","",""
|
||||
"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional``, ``tuple`` and ``variant`` are not yet implemented"
|
||||
"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional`` and ``tuple`` are not yet implemented"
|
||||
"`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","",""
|
||||
"`P3029R1 <https://wg21.link/P3029R1>`__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19",""
|
||||
"","","","","",""
|
||||
|
||||
|
@@ -242,6 +242,7 @@ namespace std {
|
||||
# include <__type_traits/is_assignable.h>
|
||||
# include <__type_traits/is_constructible.h>
|
||||
# include <__type_traits/is_convertible.h>
|
||||
# include <__type_traits/is_core_convertible.h>
|
||||
# include <__type_traits/is_destructible.h>
|
||||
# include <__type_traits/is_nothrow_assignable.h>
|
||||
# include <__type_traits/is_nothrow_constructible.h>
|
||||
@@ -1442,6 +1443,11 @@ struct __convert_to_bool {
|
||||
};
|
||||
|
||||
template <class... _Types>
|
||||
# if _LIBCPP_STD_VER >= 26
|
||||
requires(requires(const _Types& __t) {
|
||||
{ __t == __t } -> __core_convertible_to<bool>;
|
||||
} && ...)
|
||||
# endif
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
|
||||
using __variant_detail::__visitation::__variant;
|
||||
if (__lhs.index() != __rhs.index())
|
||||
@@ -1474,6 +1480,11 @@ operator<=>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
|
||||
# endif // _LIBCPP_STD_VER >= 20
|
||||
|
||||
template <class... _Types>
|
||||
# if _LIBCPP_STD_VER >= 26
|
||||
requires(requires(const _Types& __t) {
|
||||
{ __t != __t } -> __core_convertible_to<bool>;
|
||||
} && ...)
|
||||
# endif
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
|
||||
using __variant_detail::__visitation::__variant;
|
||||
if (__lhs.index() != __rhs.index())
|
||||
@@ -1484,6 +1495,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const variant<_Types...>& __lhs,
|
||||
}
|
||||
|
||||
template <class... _Types>
|
||||
# if _LIBCPP_STD_VER >= 26
|
||||
requires(requires(const _Types& __t) {
|
||||
{ __t < __t } -> __core_convertible_to<bool>;
|
||||
} && ...)
|
||||
# endif
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
|
||||
using __variant_detail::__visitation::__variant;
|
||||
if (__rhs.valueless_by_exception())
|
||||
@@ -1498,6 +1514,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const variant<_Types...>& __lhs,
|
||||
}
|
||||
|
||||
template <class... _Types>
|
||||
# if _LIBCPP_STD_VER >= 26
|
||||
requires(requires(const _Types& __t) {
|
||||
{ __t > __t } -> __core_convertible_to<bool>;
|
||||
} && ...)
|
||||
# endif
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
|
||||
using __variant_detail::__visitation::__variant;
|
||||
if (__lhs.valueless_by_exception())
|
||||
@@ -1512,6 +1533,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const variant<_Types...>& __lhs,
|
||||
}
|
||||
|
||||
template <class... _Types>
|
||||
# if _LIBCPP_STD_VER >= 26
|
||||
requires(requires(const _Types& __t) {
|
||||
{ __t <= __t } -> __core_convertible_to<bool>;
|
||||
} && ...)
|
||||
# endif
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
|
||||
using __variant_detail::__visitation::__variant;
|
||||
if (__lhs.valueless_by_exception())
|
||||
@@ -1526,6 +1552,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const variant<_Types...>& __lhs,
|
||||
}
|
||||
|
||||
template <class... _Types>
|
||||
# if _LIBCPP_STD_VER >= 26
|
||||
requires(requires(const _Types& __t) {
|
||||
{ __t >= __t } -> __core_convertible_to<bool>;
|
||||
} && ...)
|
||||
# endif
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
|
||||
using __variant_detail::__visitation::__variant;
|
||||
if (__rhs.valueless_by_exception())
|
||||
|
||||
@@ -39,8 +39,57 @@
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
#include "test_comparisons.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
#if TEST_STD_VER >= 26
|
||||
|
||||
// Test SFINAE.
|
||||
|
||||
// ==
|
||||
static_assert(HasOperatorEqual<std::variant<EqualityComparable>>);
|
||||
static_assert(HasOperatorEqual<std::variant<EqualityComparable, int, long>>);
|
||||
|
||||
static_assert(!HasOperatorEqual<std::variant<NonComparable>>);
|
||||
static_assert(!HasOperatorEqual<std::variant<NonComparable, EqualityComparable>>);
|
||||
|
||||
// >
|
||||
static_assert(HasOperatorGreaterThan<std::variant<ThreeWayComparable>>);
|
||||
static_assert(HasOperatorGreaterThan<std::variant<ThreeWayComparable, int, long>>);
|
||||
|
||||
static_assert(!HasOperatorGreaterThan<std::variant<NonComparable>>);
|
||||
static_assert(!HasOperatorGreaterThan<std::variant<NonComparable, ThreeWayComparable>>);
|
||||
|
||||
// >=
|
||||
static_assert(HasOperatorGreaterThanEqual<std::variant<ThreeWayComparable>>);
|
||||
static_assert(HasOperatorGreaterThanEqual<std::variant<ThreeWayComparable, int, long>>);
|
||||
|
||||
static_assert(!HasOperatorGreaterThanEqual<std::variant<NonComparable>>);
|
||||
static_assert(!HasOperatorGreaterThanEqual<std::variant<NonComparable, ThreeWayComparable>>);
|
||||
|
||||
// <
|
||||
static_assert(HasOperatorLessThan<std::variant<ThreeWayComparable>>);
|
||||
static_assert(HasOperatorLessThan<std::variant<ThreeWayComparable, int, long>>);
|
||||
|
||||
static_assert(!HasOperatorLessThan<std::variant<NonComparable>>);
|
||||
static_assert(!HasOperatorLessThan<std::variant<NonComparable, ThreeWayComparable>>);
|
||||
|
||||
// <=
|
||||
static_assert(HasOperatorLessThanEqual<std::variant<ThreeWayComparable>>);
|
||||
static_assert(HasOperatorLessThanEqual<std::variant<ThreeWayComparable, int, long>>);
|
||||
|
||||
static_assert(!HasOperatorLessThanEqual<std::variant<NonComparable>>);
|
||||
static_assert(!HasOperatorLessThanEqual<std::variant<NonComparable, ThreeWayComparable>>);
|
||||
|
||||
// !=
|
||||
static_assert(HasOperatorNotEqual<std::variant<EqualityComparable>>);
|
||||
static_assert(HasOperatorNotEqual<std::variant<EqualityComparable, int, long>>);
|
||||
|
||||
static_assert(!HasOperatorNotEqual<std::variant<NonComparable>>);
|
||||
static_assert(!HasOperatorNotEqual<std::variant<NonComparable, EqualityComparable>>);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
struct MakeEmptyT {
|
||||
MakeEmptyT() = default;
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
|
||||
#if TEST_STD_VER >= 26
|
||||
// expected-no-diagnostics
|
||||
#else
|
||||
struct MyBoolExplicit {
|
||||
bool value;
|
||||
constexpr explicit MyBoolExplicit(bool v) : value(v) {}
|
||||
@@ -70,8 +72,7 @@ inline constexpr MyBoolExplicit operator>=(const ComparesToMyBoolExplicit& LHS,
|
||||
return MyBoolExplicit(LHS.value >= RHS.value);
|
||||
}
|
||||
|
||||
|
||||
int main(int, char**) {
|
||||
void test() {
|
||||
using V = std::variant<int, ComparesToMyBoolExplicit>;
|
||||
V v1(42);
|
||||
V v2(101);
|
||||
@@ -83,6 +84,6 @@ int main(int, char**) {
|
||||
(void)(v1 <= v2); // expected-note {{here}}
|
||||
(void)(v1 > v2); // expected-note {{here}}
|
||||
(void)(v1 >= v2); // expected-note {{here}}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -271,12 +271,31 @@ struct PartialOrder {
|
||||
template <typename T1, typename T2 = T1>
|
||||
concept HasOperatorEqual = requires(T1 t1, T2 t2) { t1 == t2; };
|
||||
|
||||
template <typename T1, typename T2 = T1>
|
||||
concept HasOperatorGreaterThan = requires(T1 t1, T2 t2) { t1 > t2; };
|
||||
|
||||
template <typename T1, typename T2 = T1>
|
||||
concept HasOperatorGreaterThanEqual = requires(T1 t1, T2 t2) { t1 >= t2; };
|
||||
template <typename T1, typename T2 = T1>
|
||||
concept HasOperatorLessThan = requires(T1 t1, T2 t2) { t1 < t2; };
|
||||
|
||||
template <typename T1, typename T2 = T1>
|
||||
concept HasOperatorLessThanEqual = requires(T1 t1, T2 t2) { t1 <= t2; };
|
||||
|
||||
template <typename T1, typename T2 = T1>
|
||||
concept HasOperatorNotEqual = requires(T1 t1, T2 t2) { t1 != t2; };
|
||||
|
||||
template <typename T1, typename T2 = T1>
|
||||
concept HasOperatorSpaceship = requires(T1 t1, T2 t2) { t1 <=> t2; };
|
||||
|
||||
struct NonComparable {};
|
||||
static_assert(!std::equality_comparable<NonComparable>);
|
||||
static_assert(!HasOperatorEqual<NonComparable>);
|
||||
static_assert(!HasOperatorGreaterThan<NonComparable>);
|
||||
static_assert(!HasOperatorGreaterThanEqual<NonComparable>);
|
||||
static_assert(!HasOperatorLessThan<NonComparable>);
|
||||
static_assert(!HasOperatorLessThanEqual<NonComparable>);
|
||||
static_assert(!HasOperatorNotEqual<NonComparable>);
|
||||
static_assert(!HasOperatorSpaceship<NonComparable>);
|
||||
|
||||
class EqualityComparable {
|
||||
@@ -290,6 +309,28 @@ private:
|
||||
};
|
||||
static_assert(std::equality_comparable<EqualityComparable>);
|
||||
static_assert(HasOperatorEqual<EqualityComparable>);
|
||||
static_assert(HasOperatorNotEqual<EqualityComparable>);
|
||||
|
||||
class ThreeWayComparable {
|
||||
public:
|
||||
constexpr ThreeWayComparable(int value) : value_{value} {};
|
||||
|
||||
friend constexpr bool operator==(const ThreeWayComparable&, const ThreeWayComparable&) noexcept = default;
|
||||
friend constexpr std::strong_ordering
|
||||
operator<=>(const ThreeWayComparable&, const ThreeWayComparable&) noexcept = default;
|
||||
|
||||
private:
|
||||
int value_;
|
||||
};
|
||||
static_assert(std::equality_comparable<ThreeWayComparable>);
|
||||
static_assert(std::three_way_comparable<ThreeWayComparable>);
|
||||
static_assert(HasOperatorEqual<ThreeWayComparable>);
|
||||
static_assert(HasOperatorGreaterThan<ThreeWayComparable>);
|
||||
static_assert(HasOperatorGreaterThanEqual<ThreeWayComparable>);
|
||||
static_assert(HasOperatorLessThan<ThreeWayComparable>);
|
||||
static_assert(HasOperatorLessThanEqual<ThreeWayComparable>);
|
||||
static_assert(HasOperatorNotEqual<ThreeWayComparable>);
|
||||
static_assert(HasOperatorSpaceship<ThreeWayComparable>);
|
||||
|
||||
#endif // TEST_STD_VER >= 20
|
||||
|
||||
|
||||
Reference in New Issue
Block a user