Skip to content

Commit 0515b24

Browse files
committed
libstdc++: Constrain std::expected comparisons (P3379R0)
This proposal of mine has been approved by LEWG and forwarded to LWG. I expect it to be voted into the draft without significant changes. libstdc++-v3/ChangeLog: * include/bits/version.def (constrained_equality): Bump value. * include/bits/version.h: Regenerate. * include/std/expected (operator==): Add constraints and noexcept specifiers. * testsuite/20_util/optional/relops/constrained.cc: Adjust check for feature test macro. * testsuite/20_util/pair/comparison_operators/constrained.cc: Likewise. * testsuite/20_util/tuple/comparison_operators/constrained.cc: Likewise. * testsuite/20_util/variant/relops/constrained.cc: Likewise. * testsuite/20_util/expected/equality_constrained.cc: New test.
1 parent 2e30e90 commit 0515b24

File tree

8 files changed

+213
-13
lines changed

8 files changed

+213
-13
lines changed

libstdc++-v3/include/bits/version.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1256,7 +1256,7 @@ ftms = {
12561256
ftms = {
12571257
name = constrained_equality;
12581258
values = {
1259-
v = 202403;
1259+
v = 202411; // FIXME: 202403 for P2944R3, ??? for P3379R0
12601260
cxxmin = 20;
12611261
extra_cond = "__glibcxx_three_way_comparison";
12621262
};

libstdc++-v3/include/bits/version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,9 +1392,9 @@
13921392

13931393
#if !defined(__cpp_lib_constrained_equality)
13941394
# if (__cplusplus >= 202002L) && (__glibcxx_three_way_comparison)
1395-
# define __glibcxx_constrained_equality 202403L
1395+
# define __glibcxx_constrained_equality 202411L
13961396
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constrained_equality)
1397-
# define __cpp_lib_constrained_equality 202403L
1397+
# define __cpp_lib_constrained_equality 202411L
13981398
# endif
13991399
# endif
14001400
#endif /* !defined(__cpp_lib_constrained_equality) && defined(__glibcxx_want_constrained_equality) */

libstdc++-v3/include/std/expected

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#define __glibcxx_want_expected
3737
#define __glibcxx_want_freestanding_expected
38+
#define __glibcxx_want_constrained_equality
3839
#include <bits/version.h>
3940

4041
#ifdef __cpp_lib_expected // C++ >= 23 && __cpp_concepts >= 202002L
@@ -1152,10 +1153,15 @@ namespace __expected
11521153

11531154
template<typename _Up, typename _Er2>
11541155
requires (!is_void_v<_Up>)
1156+
&& requires (const _Tp& __t, const _Up& __u,
1157+
const _Er& __e, const _Er2& __e2) {
1158+
{ __t == __u } -> convertible_to<bool>;
1159+
{ __e == __e2 } -> convertible_to<bool>;
1160+
}
11551161
friend constexpr bool
11561162
operator==(const expected& __x, const expected<_Up, _Er2>& __y)
1157-
// FIXME: noexcept(noexcept(bool(*__x == *__y))
1158-
// && noexcept(bool(__x.error() == __y.error())))
1163+
noexcept(noexcept(bool(*__x == *__y))
1164+
&& noexcept(bool(__x.error() == __y.error())))
11591165
{
11601166
if (__x.has_value())
11611167
return __y.has_value() && bool(*__x == *__y);
@@ -1164,15 +1170,22 @@ namespace __expected
11641170
}
11651171

11661172
template<typename _Up>
1173+
requires (!__expected::__is_expected<_Up>)
1174+
&& requires (const _Tp& __t, const _Up& __u) {
1175+
{ __t == __u } -> convertible_to<bool>;
1176+
}
11671177
friend constexpr bool
11681178
operator==(const expected& __x, const _Up& __v)
1169-
// FIXME: noexcept(noexcept(bool(*__x == __v)))
1179+
noexcept(noexcept(bool(*__x == __v)))
11701180
{ return __x.has_value() && bool(*__x == __v); }
11711181

11721182
template<typename _Er2>
1183+
requires requires (const _Er& __e, const _Er2& __e2) {
1184+
{ __e == __e2 } -> convertible_to<bool>;
1185+
}
11731186
friend constexpr bool
11741187
operator==(const expected& __x, const unexpected<_Er2>& __e)
1175-
// FIXME: noexcept(noexcept(bool(__x.error() == __e.error())))
1188+
noexcept(noexcept(bool(__x.error() == __e.error())))
11761189
{ return !__x.has_value() && bool(__x.error() == __e.error()); }
11771190

11781191
friend constexpr void
@@ -1819,9 +1832,12 @@ namespace __expected
18191832

18201833
template<typename _Up, typename _Er2>
18211834
requires is_void_v<_Up>
1835+
&& requires (const _Er& __e, const _Er2& __e2) {
1836+
{ __e == __e2 } -> convertible_to<bool>;
1837+
}
18221838
friend constexpr bool
18231839
operator==(const expected& __x, const expected<_Up, _Er2>& __y)
1824-
// FIXME: noexcept(noexcept(bool(__x.error() == __y.error())))
1840+
noexcept(noexcept(bool(__x.error() == __y.error())))
18251841
{
18261842
if (__x.has_value())
18271843
return __y.has_value();
@@ -1830,9 +1846,12 @@ namespace __expected
18301846
}
18311847

18321848
template<typename _Er2>
1849+
requires requires (const _Er& __e, const _Er2& __e2) {
1850+
{ __e == __e2 } -> convertible_to<bool>;
1851+
}
18331852
friend constexpr bool
18341853
operator==(const expected& __x, const unexpected<_Er2>& __e)
1835-
// FIXME: noexcept(noexcept(bool(__x.error() == __e.error())))
1854+
noexcept(noexcept(bool(__x.error() == __e.error())))
18361855
{ return !__x.has_value() && bool(__x.error() == __e.error()); }
18371856

18381857
friend constexpr void
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
// { dg-do compile { target c++23 } }
2+
3+
#include <expected>
4+
5+
#ifndef __cpp_lib_constrained_equality
6+
# error "Feature-test macro for constrained_equality missing in <expected>"
7+
#elif __cpp_lib_constrained_equality < 202411L // TODO: use final value
8+
# error "Feature-test macro for constrained_equality has wrong value"
9+
#endif
10+
11+
template<typename T, typename U = T, typename E = int, typename E2 = E>
12+
concept eq_comparable
13+
= requires (const std::expected<T, E>& t, const std::expected<U, E2>& u) {
14+
t == u;
15+
};
16+
17+
static_assert( eq_comparable<int> );
18+
static_assert( eq_comparable<int, long> );
19+
static_assert( eq_comparable<short, int> );
20+
static_assert( eq_comparable<int, long, unsigned int, unsigned long> );
21+
static_assert( eq_comparable<void, const void> );
22+
23+
struct A { };
24+
static_assert( ! eq_comparable<A> );
25+
static_assert( ! eq_comparable<A, A> );
26+
static_assert( ! eq_comparable<A, int> );
27+
static_assert( ! eq_comparable<int, int, A> );
28+
static_assert( ! eq_comparable<int, int, int, A> );
29+
static_assert( ! eq_comparable<void, const void, A> );
30+
31+
struct B { };
32+
void operator==(B, B);
33+
static_assert( ! eq_comparable<B> );
34+
static_assert( ! eq_comparable<B, B> );
35+
static_assert( ! eq_comparable<B, int> );
36+
static_assert( ! eq_comparable<int, int, B> );
37+
static_assert( ! eq_comparable<int, int, int, B> );
38+
static_assert( ! eq_comparable<void, void, B> );
39+
40+
struct C { };
41+
bool operator==(C, C);
42+
static_assert( eq_comparable<C> );
43+
static_assert( eq_comparable<C, C> );
44+
static_assert( eq_comparable<C, C> );
45+
static_assert( eq_comparable<C, C, C> );
46+
static_assert( eq_comparable<int, int, C> );
47+
static_assert( ! eq_comparable<C, C, A, A> );
48+
static_assert( ! eq_comparable<C, C, A, int> );
49+
static_assert( eq_comparable<void, void, C> );
50+
51+
struct D { };
52+
int operator==(D, D);
53+
bool operator!=(D, D) = delete;
54+
static_assert( eq_comparable<D> );
55+
static_assert( eq_comparable<D, D> );
56+
static_assert( eq_comparable<int, int, D> );
57+
static_assert( eq_comparable<D, D, D> );
58+
static_assert( ! eq_comparable<D, D, D, int> );
59+
60+
struct E { };
61+
bool operator==(/* not-const */ E&, const E&);
62+
static_assert( ! eq_comparable<E> );
63+
static_assert( ! eq_comparable<E, E> );
64+
static_assert( ! eq_comparable<E, E> );
65+
static_assert( ! eq_comparable<int, int, E> );
66+
67+
bool operator==(A, B);
68+
static_assert( eq_comparable<A, B> );
69+
static_assert( eq_comparable<B, A> );
70+
static_assert( eq_comparable<int, long, B, A> );
71+
72+
int operator==(C, D);
73+
static_assert( eq_comparable<C, D> );
74+
static_assert( eq_comparable<D, C> );
75+
static_assert( eq_comparable<int, int, C, D> );
76+
static_assert( eq_comparable<int, int, D, C> );
77+
static_assert( eq_comparable<const void, void, C, D> );
78+
static_assert( eq_comparable<const void, void, D, C> );
79+
80+
template<typename T, typename U = T, typename E = int>
81+
concept eq_comparable_val
82+
= requires (const std::expected<T, E>& t, const U& u) {
83+
t == u;
84+
};
85+
86+
static_assert( eq_comparable_val<int> );
87+
static_assert( eq_comparable_val<int, long> );
88+
static_assert( eq_comparable_val<short, int> );
89+
static_assert( eq_comparable_val<int, long, unsigned> );
90+
static_assert( ! eq_comparable_val<void, const void> );
91+
92+
static_assert( ! eq_comparable_val<A> );
93+
static_assert( ! eq_comparable_val<A, A> );
94+
static_assert( ! eq_comparable_val<A, int> );
95+
static_assert( eq_comparable_val<int, int, A> );
96+
static_assert( ! eq_comparable_val<void, A> );
97+
98+
static_assert( ! eq_comparable_val<B> );
99+
static_assert( ! eq_comparable_val<B, B> );
100+
static_assert( ! eq_comparable_val<B, int> );
101+
static_assert( eq_comparable_val<int, int, B> );
102+
static_assert( ! eq_comparable_val<void, B> );
103+
104+
static_assert( eq_comparable_val<C> );
105+
static_assert( eq_comparable_val<C, C> );
106+
static_assert( eq_comparable_val<C, C> );
107+
static_assert( eq_comparable_val<C, C, C> );
108+
static_assert( eq_comparable_val<int, int, C> );
109+
static_assert( eq_comparable_val<C, C, A> );
110+
static_assert( ! eq_comparable_val<void, C> );
111+
112+
static_assert( eq_comparable_val<D> );
113+
static_assert( eq_comparable_val<D, D> );
114+
static_assert( ! eq_comparable_val<D, int> );
115+
static_assert( eq_comparable_val<int, int, D> );
116+
static_assert( eq_comparable_val<D, D, D> );
117+
118+
static_assert( ! eq_comparable_val<E> );
119+
static_assert( ! eq_comparable_val<E, E> );
120+
static_assert( ! eq_comparable_val<E, int> );
121+
static_assert( eq_comparable_val<int, int, E> );
122+
123+
static_assert( eq_comparable_val<A, B> );
124+
static_assert( eq_comparable_val<B, A> );
125+
126+
static_assert( eq_comparable_val<C, D> );
127+
static_assert( ! eq_comparable_val<D, C> );
128+
129+
template<typename E, typename U, typename T = int>
130+
concept eq_comparable_unex
131+
= requires (const std::expected<T, E>& t, const std::unexpected<U>& u) {
132+
t == u;
133+
};
134+
135+
static_assert( eq_comparable_unex<int, int> );
136+
static_assert( eq_comparable_unex<int, long> );
137+
static_assert( eq_comparable_unex<short, int> );
138+
static_assert( eq_comparable_unex<int, int, void> );
139+
static_assert( eq_comparable_unex<int, long, void> );
140+
static_assert( eq_comparable_unex<short, int, void> );
141+
142+
static_assert( ! eq_comparable_unex<A, A> );
143+
static_assert( ! eq_comparable_unex<A, int> );
144+
static_assert( ! eq_comparable_unex<int, A> );
145+
static_assert( ! eq_comparable_unex<A, A, void> );
146+
static_assert( ! eq_comparable_unex<A, int, void> );
147+
static_assert( ! eq_comparable_unex<int, A, void> );
148+
149+
static_assert( ! eq_comparable_unex<B, B> );
150+
static_assert( ! eq_comparable_unex<B, int> );
151+
static_assert( ! eq_comparable_unex<int, B> );
152+
static_assert( ! eq_comparable_unex<B, B, void> );
153+
static_assert( ! eq_comparable_unex<B, int, void> );
154+
static_assert( ! eq_comparable_unex<int, B, void> );
155+
156+
static_assert( eq_comparable_unex<C, C> );
157+
static_assert( eq_comparable_unex<C, C, void> );
158+
159+
static_assert( eq_comparable_unex<D, D> );
160+
static_assert( ! eq_comparable_unex<D, int> );
161+
static_assert( ! eq_comparable_unex<int, D> );
162+
static_assert( eq_comparable_unex<D, D, void> );
163+
static_assert( ! eq_comparable_unex<D, int, void> );
164+
static_assert( ! eq_comparable_unex<int, D, void> );
165+
166+
static_assert( ! eq_comparable_unex<E, E> );
167+
static_assert( ! eq_comparable_unex<E, int> );
168+
static_assert( ! eq_comparable_unex<int, E> );
169+
static_assert( ! eq_comparable_unex<E, E, void> );
170+
static_assert( ! eq_comparable_unex<E, int, void> );
171+
static_assert( ! eq_comparable_unex<int, E, void> );
172+
173+
static_assert( eq_comparable_unex<A, B> );
174+
static_assert( eq_comparable_unex<B, A> );
175+
static_assert( eq_comparable_unex<A, B, void> );
176+
static_assert( eq_comparable_unex<B, A, void> );
177+
178+
static_assert( eq_comparable_unex<C, D> );
179+
static_assert( ! eq_comparable_unex<D, C> );
180+
static_assert( eq_comparable_unex<C, D, void> );
181+
static_assert( ! eq_comparable_unex<D, C, void> );

libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#ifndef __cpp_lib_constrained_equality
66
# error "Feature-test macro for constrained_equality missing"
7-
#elif __cpp_lib_constrained_equality != 202403
7+
#elif __cpp_lib_constrained_equality < 202403L
88
# error "Feature-test macro for constrained_equality has wrong value"
99
#endif
1010

libstdc++-v3/testsuite/20_util/pair/comparison_operators/constrained.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#ifndef __cpp_lib_constrained_equality
66
# error "Feature-test macro for constrained_equality missing"
7-
#elif __cpp_lib_constrained_equality != 202403
7+
#elif __cpp_lib_constrained_equality < 202403L
88
# error "Feature-test macro for constrained_equality has wrong value"
99
#endif
1010

libstdc++-v3/testsuite/20_util/tuple/comparison_operators/constrained.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#ifndef __cpp_lib_constrained_equality
66
# error "Feature-test macro for constrained_equality missing"
7-
#elif __cpp_lib_constrained_equality != 202403
7+
#elif __cpp_lib_constrained_equality < 202403L
88
# error "Feature-test macro for constrained_equality has wrong value"
99
#endif
1010

libstdc++-v3/testsuite/20_util/variant/relops/constrained.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#ifndef __cpp_lib_constrained_equality
66
# error "Feature-test macro for constrained_equality missing"
7-
#elif __cpp_lib_constrained_equality != 202403
7+
#elif __cpp_lib_constrained_equality < 202403L
88
# error "Feature-test macro for constrained_equality has wrong value"
99
#endif
1010

0 commit comments

Comments
 (0)