Skip to content

Commit f2f4b55

Browse files
authored
[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)
1 parent 88297cc commit f2f4b55

File tree

5 files changed

+128
-6
lines changed

5 files changed

+128
-6
lines changed

libcxx/docs/Status/Cxx2cPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"`P2248R8 <https://wg21.link/P2248R8>`__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","",""
6060
"`P2810R4 <https://wg21.link/P2810R4>`__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","",""
6161
"`P1068R11 <https://wg21.link/P1068R11>`__","Vector API for random number generation","2024-03 (Tokyo)","","",""
62-
"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional``, ``tuple`` and ``variant`` are not yet implemented"
62+
"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional`` and ``tuple`` are not yet implemented"
6363
"`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","",""
6464
"`P3029R1 <https://wg21.link/P3029R1>`__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19",""
6565
"","","","","",""

libcxx/include/variant

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ namespace std {
242242
# include <__type_traits/is_assignable.h>
243243
# include <__type_traits/is_constructible.h>
244244
# include <__type_traits/is_convertible.h>
245+
# include <__type_traits/is_core_convertible.h>
245246
# include <__type_traits/is_destructible.h>
246247
# include <__type_traits/is_nothrow_assignable.h>
247248
# include <__type_traits/is_nothrow_constructible.h>
@@ -1442,6 +1443,11 @@ struct __convert_to_bool {
14421443
};
14431444

14441445
template <class... _Types>
1446+
# if _LIBCPP_STD_VER >= 26
1447+
requires(requires(const _Types& __t) {
1448+
{ __t == __t } -> __core_convertible_to<bool>;
1449+
} && ...)
1450+
# endif
14451451
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
14461452
using __variant_detail::__visitation::__variant;
14471453
if (__lhs.index() != __rhs.index())
@@ -1474,6 +1480,11 @@ operator<=>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
14741480
# endif // _LIBCPP_STD_VER >= 20
14751481

14761482
template <class... _Types>
1483+
# if _LIBCPP_STD_VER >= 26
1484+
requires(requires(const _Types& __t) {
1485+
{ __t != __t } -> __core_convertible_to<bool>;
1486+
} && ...)
1487+
# endif
14771488
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
14781489
using __variant_detail::__visitation::__variant;
14791490
if (__lhs.index() != __rhs.index())
@@ -1484,6 +1495,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const variant<_Types...>& __lhs,
14841495
}
14851496

14861497
template <class... _Types>
1498+
# if _LIBCPP_STD_VER >= 26
1499+
requires(requires(const _Types& __t) {
1500+
{ __t < __t } -> __core_convertible_to<bool>;
1501+
} && ...)
1502+
# endif
14871503
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
14881504
using __variant_detail::__visitation::__variant;
14891505
if (__rhs.valueless_by_exception())
@@ -1498,6 +1514,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const variant<_Types...>& __lhs,
14981514
}
14991515

15001516
template <class... _Types>
1517+
# if _LIBCPP_STD_VER >= 26
1518+
requires(requires(const _Types& __t) {
1519+
{ __t > __t } -> __core_convertible_to<bool>;
1520+
} && ...)
1521+
# endif
15011522
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
15021523
using __variant_detail::__visitation::__variant;
15031524
if (__lhs.valueless_by_exception())
@@ -1512,6 +1533,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const variant<_Types...>& __lhs,
15121533
}
15131534

15141535
template <class... _Types>
1536+
# if _LIBCPP_STD_VER >= 26
1537+
requires(requires(const _Types& __t) {
1538+
{ __t <= __t } -> __core_convertible_to<bool>;
1539+
} && ...)
1540+
# endif
15151541
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
15161542
using __variant_detail::__visitation::__variant;
15171543
if (__lhs.valueless_by_exception())
@@ -1526,6 +1552,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const variant<_Types...>& __lhs,
15261552
}
15271553

15281554
template <class... _Types>
1555+
# if _LIBCPP_STD_VER >= 26
1556+
requires(requires(const _Types& __t) {
1557+
{ __t >= __t } -> __core_convertible_to<bool>;
1558+
} && ...)
1559+
# endif
15291560
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
15301561
using __variant_detail::__visitation::__variant;
15311562
if (__rhs.valueless_by_exception())

libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,57 @@
3939
#include <utility>
4040
#include <variant>
4141

42+
#include "test_comparisons.h"
4243
#include "test_macros.h"
4344

45+
#if TEST_STD_VER >= 26
46+
47+
// Test SFINAE.
48+
49+
// ==
50+
static_assert(HasOperatorEqual<std::variant<EqualityComparable>>);
51+
static_assert(HasOperatorEqual<std::variant<EqualityComparable, int, long>>);
52+
53+
static_assert(!HasOperatorEqual<std::variant<NonComparable>>);
54+
static_assert(!HasOperatorEqual<std::variant<NonComparable, EqualityComparable>>);
55+
56+
// >
57+
static_assert(HasOperatorGreaterThan<std::variant<ThreeWayComparable>>);
58+
static_assert(HasOperatorGreaterThan<std::variant<ThreeWayComparable, int, long>>);
59+
60+
static_assert(!HasOperatorGreaterThan<std::variant<NonComparable>>);
61+
static_assert(!HasOperatorGreaterThan<std::variant<NonComparable, ThreeWayComparable>>);
62+
63+
// >=
64+
static_assert(HasOperatorGreaterThanEqual<std::variant<ThreeWayComparable>>);
65+
static_assert(HasOperatorGreaterThanEqual<std::variant<ThreeWayComparable, int, long>>);
66+
67+
static_assert(!HasOperatorGreaterThanEqual<std::variant<NonComparable>>);
68+
static_assert(!HasOperatorGreaterThanEqual<std::variant<NonComparable, ThreeWayComparable>>);
69+
70+
// <
71+
static_assert(HasOperatorLessThan<std::variant<ThreeWayComparable>>);
72+
static_assert(HasOperatorLessThan<std::variant<ThreeWayComparable, int, long>>);
73+
74+
static_assert(!HasOperatorLessThan<std::variant<NonComparable>>);
75+
static_assert(!HasOperatorLessThan<std::variant<NonComparable, ThreeWayComparable>>);
76+
77+
// <=
78+
static_assert(HasOperatorLessThanEqual<std::variant<ThreeWayComparable>>);
79+
static_assert(HasOperatorLessThanEqual<std::variant<ThreeWayComparable, int, long>>);
80+
81+
static_assert(!HasOperatorLessThanEqual<std::variant<NonComparable>>);
82+
static_assert(!HasOperatorLessThanEqual<std::variant<NonComparable, ThreeWayComparable>>);
83+
84+
// !=
85+
static_assert(HasOperatorNotEqual<std::variant<EqualityComparable>>);
86+
static_assert(HasOperatorNotEqual<std::variant<EqualityComparable, int, long>>);
87+
88+
static_assert(!HasOperatorNotEqual<std::variant<NonComparable>>);
89+
static_assert(!HasOperatorNotEqual<std::variant<NonComparable, EqualityComparable>>);
90+
91+
#endif
92+
4493
#ifndef TEST_HAS_NO_EXCEPTIONS
4594
struct MakeEmptyT {
4695
MakeEmptyT() = default;

libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.verify.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@
4141

4242
#include "test_macros.h"
4343

44-
44+
#if TEST_STD_VER >= 26
45+
// expected-no-diagnostics
46+
#else
4547
struct MyBoolExplicit {
4648
bool value;
4749
constexpr explicit MyBoolExplicit(bool v) : value(v) {}
@@ -70,8 +72,7 @@ inline constexpr MyBoolExplicit operator>=(const ComparesToMyBoolExplicit& LHS,
7072
return MyBoolExplicit(LHS.value >= RHS.value);
7173
}
7274

73-
74-
int main(int, char**) {
75+
void test() {
7576
using V = std::variant<int, ComparesToMyBoolExplicit>;
7677
V v1(42);
7778
V v2(101);
@@ -83,6 +84,6 @@ int main(int, char**) {
8384
(void)(v1 <= v2); // expected-note {{here}}
8485
(void)(v1 > v2); // expected-note {{here}}
8586
(void)(v1 >= v2); // expected-note {{here}}
86-
87-
return 0;
8887
}
88+
89+
#endif

libcxx/test/support/test_comparisons.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,31 @@ struct PartialOrder {
271271
template <typename T1, typename T2 = T1>
272272
concept HasOperatorEqual = requires(T1 t1, T2 t2) { t1 == t2; };
273273

274+
template <typename T1, typename T2 = T1>
275+
concept HasOperatorGreaterThan = requires(T1 t1, T2 t2) { t1 > t2; };
276+
277+
template <typename T1, typename T2 = T1>
278+
concept HasOperatorGreaterThanEqual = requires(T1 t1, T2 t2) { t1 >= t2; };
279+
template <typename T1, typename T2 = T1>
280+
concept HasOperatorLessThan = requires(T1 t1, T2 t2) { t1 < t2; };
281+
282+
template <typename T1, typename T2 = T1>
283+
concept HasOperatorLessThanEqual = requires(T1 t1, T2 t2) { t1 <= t2; };
284+
285+
template <typename T1, typename T2 = T1>
286+
concept HasOperatorNotEqual = requires(T1 t1, T2 t2) { t1 != t2; };
287+
274288
template <typename T1, typename T2 = T1>
275289
concept HasOperatorSpaceship = requires(T1 t1, T2 t2) { t1 <=> t2; };
276290

277291
struct NonComparable {};
278292
static_assert(!std::equality_comparable<NonComparable>);
279293
static_assert(!HasOperatorEqual<NonComparable>);
294+
static_assert(!HasOperatorGreaterThan<NonComparable>);
295+
static_assert(!HasOperatorGreaterThanEqual<NonComparable>);
296+
static_assert(!HasOperatorLessThan<NonComparable>);
297+
static_assert(!HasOperatorLessThanEqual<NonComparable>);
298+
static_assert(!HasOperatorNotEqual<NonComparable>);
280299
static_assert(!HasOperatorSpaceship<NonComparable>);
281300

282301
class EqualityComparable {
@@ -290,6 +309,28 @@ class EqualityComparable {
290309
};
291310
static_assert(std::equality_comparable<EqualityComparable>);
292311
static_assert(HasOperatorEqual<EqualityComparable>);
312+
static_assert(HasOperatorNotEqual<EqualityComparable>);
313+
314+
class ThreeWayComparable {
315+
public:
316+
constexpr ThreeWayComparable(int value) : value_{value} {};
317+
318+
friend constexpr bool operator==(const ThreeWayComparable&, const ThreeWayComparable&) noexcept = default;
319+
friend constexpr std::strong_ordering
320+
operator<=>(const ThreeWayComparable&, const ThreeWayComparable&) noexcept = default;
321+
322+
private:
323+
int value_;
324+
};
325+
static_assert(std::equality_comparable<ThreeWayComparable>);
326+
static_assert(std::three_way_comparable<ThreeWayComparable>);
327+
static_assert(HasOperatorEqual<ThreeWayComparable>);
328+
static_assert(HasOperatorGreaterThan<ThreeWayComparable>);
329+
static_assert(HasOperatorGreaterThanEqual<ThreeWayComparable>);
330+
static_assert(HasOperatorLessThan<ThreeWayComparable>);
331+
static_assert(HasOperatorLessThanEqual<ThreeWayComparable>);
332+
static_assert(HasOperatorNotEqual<ThreeWayComparable>);
333+
static_assert(HasOperatorSpaceship<ThreeWayComparable>);
293334

294335
#endif // TEST_STD_VER >= 20
295336

0 commit comments

Comments
 (0)