Skip to content

Commit 12fc430

Browse files
committed
[libc++][pair] P2944R3: Constrain pair equality operator
Implements https://wg21.link/P2944R3 (partially): - [pairs.spec](https://eel.is/c++draft/pairs.spec) Related issues: - Related to #105424 - Related to #118135
1 parent 642481a commit 12fc430

File tree

4 files changed

+102
-2
lines changed

4 files changed

+102
-2
lines changed

libcxx/include/__utility/pair.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <__compare/common_comparison_category.h>
1313
#include <__compare/synth_three_way.h>
14+
#include <__concepts/boolean_testable.h>
1415
#include <__concepts/different_from.h>
1516
#include <__config>
1617
#include <__cstddef/size_t.h>
@@ -447,7 +448,14 @@ pair(_T1, _T2) -> pair<_T1, _T2>;
447448

448449
template <class _T1, class _T2, class _U1, class _U2>
449450
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
450-
operator==(const pair<_T1, _T2>& __x, const pair<_U1, _U2>& __y) {
451+
operator==(const pair<_T1, _T2>& __x, const pair<_U1, _U2>& __y)
452+
#if _LIBCPP_STD_VER >= 26
453+
requires requires {
454+
{ __x.first == __y.first } -> __boolean_testable;
455+
{ __x.second == __y.second } -> __boolean_testable;
456+
}
457+
#endif
458+
{
451459
return __x.first == __y.first && __x.second == __y.second;
452460
}
453461

libcxx/include/tuple

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ template <class... Types>
216216
# include <__compare/common_comparison_category.h>
217217
# include <__compare/ordering.h>
218218
# include <__compare/synth_three_way.h>
219+
# include <__concepts/boolean_testable.h>
219220
# include <__config>
220221
# include <__cstddef/size_t.h>
221222
# include <__fwd/array.h>
@@ -1160,8 +1161,16 @@ struct __tuple_equal<0> {
11601161

11611162
template <class... _Tp, class... _Up>
11621163
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
1163-
operator==(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) {
1164+
operator==(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
1165+
# if _LIBCPP_STD_VER >= 26
1166+
requires requires {
1167+
{ sizeof...(_Tp) == sizeof...(_Up) } -> __boolean_testable;
1168+
}
1169+
# endif
1170+
{
1171+
# if _LIBCPP_STD_VER < 26
11641172
static_assert(sizeof...(_Tp) == sizeof...(_Up), "Can't compare tuples of different sizes");
1173+
# endif
11651174
return __tuple_equal<sizeof...(_Tp)>()(__x, __y);
11661175
}
11671176

libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_comparison.verify.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@
2121

2222
#include <tuple>
2323

24+
#include "test_macros.h"
25+
2426
void f(std::tuple<int> t1, std::tuple<int, long> t2) {
2527
// We test only the core comparison operators and trust that the others
2628
// fall back on the same implementations prior to C++20.
29+
#if TEST_STD_VER >= 26
30+
static_cast<void>(t1 == t2);
31+
#else
2732
static_cast<void>(t1 == t2); // expected-error@*:* {{}}
33+
#endif
2834
static_cast<void>(t1 < t2); // expected-error@*:* {{}}
2935
}

libcxx/test/std/utilities/utility/pairs/pairs.spec/comparison.pass.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,86 @@
1919

2020
#include <utility>
2121
#include <cassert>
22+
#include <concepts>
2223

2324
#include "test_macros.h"
2425

26+
#if TEST_STD_VER >= 26
27+
28+
// template <typename T>
29+
// class EqualityComparable {
30+
// public:
31+
// constexpr EqualityComparable(T value) : value_{value} {};
32+
33+
// friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default;
34+
35+
// private:
36+
// T value_;
37+
// };
38+
39+
// static_assert(std::equality_comparable<EqualityComparable<std::pair<int,int>>>);
40+
// // static_assert(std::equality_comparable<EqualityComparable<std::pair<int,int>>, std::pair<int,int>>);
41+
// // static_assert(std::equality_comparable<EqualityComparable<std::pair<int,int>>, EqualityComparable<std::pair<int,int>>>);
42+
// // static_assert(std::equality_comparable<EqualityComparable<std::pair<int,int>>, std::pair<int,int>, std::pair<int,int>>);
43+
// // static_assert(std::equality_comparable<EqualityComparable<std::pair<int,int>>, EqualityComparable<std::pair<int,int>>, std::pair<int,int>>);
44+
// // static_assert(std::equality_comparable<EqualityComparable<std::pair<int,int>>, std::pair<int,int>, EqualityComparable<std::pair<int,int>>>);
45+
// // static_assert(std::equality_comparable<EqualityComparable<std::pair<int,int>>, EqualityComparable<std::pair<int,int>>, EqualityComparable<std::pair<int,int>>>);
46+
// static_assert(std::equality_comparable<EqualityComparable<std::pair<int,int>>, std::pair<int,int>, std::pair<int,int>, EqualityComparable<std::pair<int,int>>>);
47+
// static_assert(EqualityComparable<std::pair<int,int>>{std::pair{94, 82}} == EqualityComparable<std::pair<int,int>>{std::pair{94, 82}});
48+
// static_assert(EqualityComparable<std::pair<int,int>>{std::pair{94, 82}} != EqualityComparable<std::pair<int,int>>{std::pair{82, 82}});
49+
50+
struct EqualityComparable {
51+
constexpr EqualityComparable(int value) : value_{value} {};
52+
53+
friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default;
54+
55+
int value_;
56+
};
57+
58+
static_assert(std::equality_comparable<EqualityComparable>);
59+
static_assert(EqualityComparable{94} == EqualityComparable{94});
60+
static_assert(EqualityComparable{94} != EqualityComparable{82});
61+
62+
static_assert(std::equality_comparable<std::pair<EqualityComparable, EqualityComparable>>);
63+
static_assert(std::pair{EqualityComparable{94}, EqualityComparable{94}} ==
64+
std::pair{EqualityComparable{94}, EqualityComparable{94}});
65+
static_assert(std::pair{EqualityComparable{82}, EqualityComparable{94}} !=
66+
std::pair{EqualityComparable{94}, EqualityComparable{94}});
67+
static_assert(std::pair{EqualityComparable{94}, EqualityComparable{82}} !=
68+
std::pair{EqualityComparable{94}, EqualityComparable{94}});
69+
70+
struct NonComparable {};
71+
72+
static_assert(!std::three_way_comparable<std::pair<NonComparable, NonComparable>>);
73+
static_assert(!std::three_way_comparable<std::pair<EqualityComparable, NonComparable>>);
74+
static_assert(!std::three_way_comparable<std::pair<NonComparable, EqualityComparable>>);
75+
76+
static_assert(!std::equality_comparable<std::pair<EqualityComparable, NonComparable>>);
77+
static_assert(!std::equality_comparable<std::pair<NonComparable, EqualityComparable>>);
78+
79+
80+
template <typename T, typename U>
81+
concept HasCompare = requires(T t, U u) {
82+
{ t == u } -> std::same_as<bool>;
83+
{ t != u } -> std::same_as<bool>;
84+
{ t < u } -> std::same_as<bool>;
85+
{ t > u } -> std::same_as<bool>;
86+
{ t <= u } -> std::same_as<bool>;
87+
{ t >= u } -> std::same_as<bool>;
88+
};
89+
90+
template <typename T, typename U>
91+
concept HasCompare = requires(std::pair p1, std::pair p2) {
92+
{ t == u } -> std::same_as<bool>;
93+
{ t != u } -> std::same_as<bool>;
94+
{ t < u } -> std::same_as<bool>;
95+
{ t > u } -> std::same_as<bool>;
96+
{ t <= u } -> std::same_as<bool>;
97+
{ t >= u } -> std::same_as<bool>;
98+
};
99+
100+
#endif // TEST_STD_VER >= 26
101+
25102
int main(int, char**)
26103
{
27104
{

0 commit comments

Comments
 (0)