Skip to content

Commit f2cd12d

Browse files
jensmaurertkoeppe
authored andcommitted
P2404R3 Move-only types for equality_comparable_with, totally_ordered_with, and three_way_comparable_with
1 parent 2dbac7e commit f2cd12d

File tree

3 files changed

+111
-22
lines changed

3 files changed

+111
-22
lines changed

source/compatibility.tex

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,33 @@
133133
Valid \CppXX{} code that \tcode{\#include}{s} headers with these names may be
134134
invalid in this revision of \Cpp{}.
135135

136+
\rSec2[diff.cpp20.concepts]{\ref{concepts}: concepts library}
137+
138+
\diffref{cmp.concept,concept.equalitycomparable,concept.totallyordered}
139+
\change
140+
Replace \tcode{common_reference_with} in \tcode{three_way_comparable_with},
141+
\tcode{equality_comparable_with}, and \tcode{totally_ordered_with}
142+
with an exposition-only concept.
143+
\rationale
144+
Allow uncopyable, but movable, types to model these concepts.
145+
\effect
146+
Valid \CppXX{} code relying on subsumption
147+
with \tcode{common_reference_with}
148+
may fail to compile in this revision of \Cpp{}. For example:
149+
\begin{codeblock}
150+
template<class T, class U>
151+
requires @\libconcept{equality_comparable_with}@<T, U>
152+
bool attempted_equals(const T&, const U& u); // previously selected overload
153+
154+
template<class T, class U>
155+
requires @\libconcept{common_reference_with}@<const remove_reference_t<T>&, const remove_reference_t<U>&>
156+
bool attempted_equals(const T& t, const U& u); // ambiguous overload; previously
157+
// rejected by partial ordering
158+
bool test(shared_ptr<int> p) {
159+
return attempted_equals(p, nullptr); // ill-formed; previously well-formed
160+
}
161+
\end{codeblock}
162+
136163
\rSec2[diff.cpp20.utilities]{\ref{utilities}: general utilities library}
137164

138165
\diffref{format}

source/concepts.tex

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,16 @@
849849
Subclause \ref{concepts.compare} describes concepts that establish relationships and orderings
850850
on values of possibly differing object types.
851851

852+
\pnum
853+
Given an expression \tcode{E} and a type \tcode{C},
854+
let \tcode{\exposid{CONVERT_TO_LVALUE}<C>(E)} be:
855+
\begin{itemize}
856+
\item
857+
\tcode{static_cast<const C\&>(as_const(E))} if that is a valid expression, and
858+
\item
859+
\tcode{static_cast<const C\&>(std::move(E))} otherwise.
860+
\end{itemize}
861+
852862
\rSec2[concept.booleantestable]{Boolean testability}
853863

854864
\pnum
@@ -985,6 +995,42 @@
985995
model \exposconcept{boolean-testable}.
986996
\end{example}
987997

998+
\rSec2[concept.comparisoncommontype]{Comparison common types}
999+
1000+
\begin{itemdecl}
1001+
template<class T, class U, class C = common_reference_t<const T&, const U&>>
1002+
concept @\defexposconcept{comparison-common-type-with-impl}@ = // \expos
1003+
@\libconcept{same_as}@<common_reference_t<const T&, const U&>,
1004+
common_reference_t<const U&, const T&>> &&
1005+
requires {
1006+
requires @\libconcept{convertible_to}@<const T&, const C&> || @\libconcept{convertible_to}@<T, const C&>;
1007+
requires @\libconcept{convertible_to}@<const U&, const C&> || @\libconcept{convertible_to}@<U, const C&>;
1008+
};
1009+
1010+
template<class T, class U>
1011+
concept @\defexposconcept{comparison-common-type-with}@ = // \expos
1012+
@\exposconcept{comparison-common-type-with-impl}@<remove_cvref_t<T>, remove_cvref_t<U>>;
1013+
\end{itemdecl}
1014+
1015+
\pnum
1016+
Let \tcode{C} be \tcode{common_reference_t<const T\&, const U\&>}.
1017+
Let \tcode{t1} and \tcode{t2} be equality-preserving expressions
1018+
that are lvalues of type \tcode{remove_cvref_t<T>}, and
1019+
let \tcode{u1} and \tcode{u2} be equality-preserving expressions
1020+
that are lvalues of type \tcode{remove_cvref_t<U>}.
1021+
\tcode{T} and \tcode{U} model
1022+
\tcode{\exposconcept{comparison-common-type-with}<T, U>} only if:
1023+
\begin{itemize}
1024+
\item
1025+
\tcode{\exposid{CONVERT_TO_LVALUE}<C>(t1)} equals
1026+
\tcode{\exposid{CONVERT_TO_LVALUE}<C>(t2)}
1027+
if and only if \tcode{t1} equals \tcode{t2}, and
1028+
\item
1029+
\tcode{\exposid{CONVERT_TO_LVALUE}<C>(u1)} equals
1030+
\tcode{\exposid{CONVERT_TO_LVALUE}<C>(u2)}
1031+
if and only if \tcode{u1} equals \tcode{u2}
1032+
\end{itemize}
1033+
9881034
\rSec2[concept.equalitycomparable]{Concept \cname{equality_comparable}}
9891035

9901036
\begin{itemdecl}
@@ -1039,7 +1085,7 @@
10391085
template<class T, class U>
10401086
concept @\deflibconcept{equality_comparable_with}@ =
10411087
@\libconcept{equality_comparable}@<T> && @\libconcept{equality_comparable}@<U> &&
1042-
@\libconcept{common_reference_with}@<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
1088+
@\exposconcept{comparison-common-type-with}@<T, U> &&
10431089
@\libconcept{equality_comparable}@<
10441090
common_reference_t<
10451091
const remove_reference_t<T>&,
@@ -1050,15 +1096,21 @@
10501096
\begin{itemdescr}
10511097
\pnum
10521098
Given types \tcode{T} and \tcode{U},
1053-
let \tcode{t} be an lvalue of type \tcode{const remove_reference_t<T>},
1054-
\tcode{u} be an lvalue of type \tcode{const remove_reference_t<U>},
1055-
and \tcode{C} be:
1099+
let \tcode{t} and \tcode{t2} be lvalues
1100+
denoting distinct equal objects of types \tcode{const remove_reference_t<T>} and
1101+
\tcode{remove_cvref_t<T>}, respectively,
1102+
let \tcode{u} and \tcode{u2} be lvalues
1103+
denoting distinct equal objects of types \tcode{const remove_reference_t<U>} and
1104+
\tcode{remove_cvref_t<U>}, respectively, and
1105+
let \tcode{C} be:
10561106
\begin{codeblock}
10571107
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>
10581108
\end{codeblock}
10591109
\tcode{T} and \tcode{U} model
10601110
\tcode{\libconcept{equality_comparable_with}<T, U>} only if
1061-
\tcode{bool(t == u) == bool(C(t) == C(u))}.
1111+
\begin{codeblock}
1112+
bool(t == u) == bool(@\exposid{CONVERT_TO_LVALUE}@<C>(t2) == @\exposid{CONVERT_TO_LVALUE}@<C>(u2))
1113+
\end{codeblock}
10621114
\end{itemdescr}
10631115

10641116
\rSec2[concept.totallyordered]{Concept \cname{totally_ordered}}
@@ -1101,24 +1153,27 @@
11011153
\begin{itemdescr}
11021154
\pnum
11031155
Given types \tcode{T} and \tcode{U},
1104-
let \tcode{t} be an lvalue of type \tcode{const remove_reference_t<T>},
1105-
\tcode{u} be an lvalue of type \tcode{const remove_reference_t<U>},
1106-
and \tcode{C} be:
1156+
let \tcode{t} and \tcode{t2} be lvalues
1157+
denoting distinct equal objects of types \tcode{const remove_reference_t<T>} and
1158+
\tcode{remove_cvref_t<T>}, respectively,
1159+
let \tcode{u} and \tcode{u2} be lvalues
1160+
denoting distinct equal objects of types \tcode{const remove_reference_t<U>} and
1161+
\tcode{remove_cvref_t<U>}, respectively, and
1162+
let \tcode{C} be:
11071163
\begin{codeblock}
11081164
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>
11091165
\end{codeblock}
11101166
\tcode{T} and \tcode{U} model
11111167
\tcode{\libconcept{totally_ordered_with}<T, U>} only if
1112-
11131168
\begin{itemize}
1114-
\item \tcode{bool(t < u) == bool(C(t) < C(u)).}
1115-
\item \tcode{bool(t > u) == bool(C(t) > C(u)).}
1116-
\item \tcode{bool(t <= u) == bool(C(t) <= C(u)).}
1117-
\item \tcode{bool(t >= u) == bool(C(t) >= C(u)).}
1118-
\item \tcode{bool(u < t) == bool(C(u) < C(t)).}
1119-
\item \tcode{bool(u > t) == bool(C(u) > C(t)).}
1120-
\item \tcode{bool(u <= t) == bool(C(u) <= C(t)).}
1121-
\item \tcode{bool(u >= t) == bool(C(u) >= C(t)).}
1169+
\item \tcode{bool(t < u) == bool(\exposid{CONVERT_TO_LVALUE}<C>(t2) < \exposid{CONVERT_TO_LVALUE}<C>(u2))}.
1170+
\item \tcode{bool(t > u) == bool(\exposid{CONVERT_TO_LVALUE}<C>(t2) > \exposid{CONVERT_TO_LVALUE}<C>(u2))}.
1171+
\item \tcode{bool(t <= u) == bool(\exposid{CONVERT_TO_LVALUE}<C>(t2) <= \exposid{CONVERT_TO_LVALUE}<C>(u2))}.
1172+
\item \tcode{bool(t >= u) == bool(\exposid{CONVERT_TO_LVALUE}<C>(t2) >= \exposid{CONVERT_TO_LVALUE}<C>(u2))}.
1173+
\item \tcode{bool(u < t) == bool(\exposid{CONVERT_TO_LVALUE}<C>(u2) < \exposid{CONVERT_TO_LVALUE}<C>(t2))}.
1174+
\item \tcode{bool(u > t) == bool(\exposid{CONVERT_TO_LVALUE}<C>(u2) > \exposid{CONVERT_TO_LVALUE}<C>(t2))}.
1175+
\item \tcode{bool(u <= t) == bool(\exposid{CONVERT_TO_LVALUE}<C>(u2) <= \exposid{CONVERT_TO_LVALUE}<C>(t2))}.
1176+
\item \tcode{bool(u >= t) == bool(\exposid{CONVERT_TO_LVALUE}<C>(u2) >= \exposid{CONVERT_TO_LVALUE}<C>(t2))}.
11221177
\end{itemize}
11231178
\end{itemdescr}
11241179

source/support.tex

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@
589589
#define @\defnlibxname{cpp_lib_chrono_udls}@ 201304L // also in \libheader{chrono}
590590
#define @\defnlibxname{cpp_lib_clamp}@ 201603L // also in \libheader{algorithm}
591591
#define @\defnlibxname{cpp_lib_complex_udls}@ 201309L // also in \libheader{complex}
592-
#define @\defnlibxname{cpp_lib_concepts}@ 202002L // also in \libheader{concepts}
592+
#define @\defnlibxname{cpp_lib_concepts}@ 202207L // also in \libheader{concepts}, \libheader{compare}
593593
#define @\defnlibxname{cpp_lib_constexpr_algorithms}@ 201806L // also in \libheader{algorithm}
594594
#define @\defnlibxname{cpp_lib_constexpr_charconv}@ 202207L // also in \libheader{charconv}
595595
#define @\defnlibxname{cpp_lib_constexpr_cmath}@ 202202L // also in \libheader{cmath}, \libheader{cstdlib}
@@ -4830,7 +4830,7 @@
48304830
concept @\deflibconcept{three_way_comparable_with}@ =
48314831
@\libconcept{three_way_comparable}@<T, Cat> &&
48324832
@\libconcept{three_way_comparable}@<U, Cat> &&
4833-
@\libconcept{common_reference_with}@<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
4833+
@\exposconcept{comparison-common-type-with}@<T, U> &&
48344834
@\libconcept{three_way_comparable}@<
48354835
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>, Cat> &&
48364836
@\exposconcept{weakly-equality-comparable-with}@<T, U> &&
@@ -4842,11 +4842,17 @@
48424842
\end{codeblock}
48434843

48444844
\pnum
4845-
Let \tcode{t} and \tcode{u} be lvalues
4845+
Let \tcode{t} and \tcode{t2} be lvalues
4846+
denoting distinct equal objects
48464847
of types \tcode{const remove_reference_t<T>} and
4847-
\tcode{const remove_reference_t<U>}, respectively.
4848+
\tcode{remove_cvref_t<T>}, respectively, and
4849+
let \tcode{u} and \tcode{u2} be lvalues denoting distinct equal objects
4850+
of types \tcode{const remove_reference_t<U>} and
4851+
\tcode{remove_cvref_t<U>}, respectively.
48484852
Let \tcode{C} be
48494853
\tcode{common_reference_t<const remove_reference_t<T>\&, const remove_reference_t<U>\&>}.
4854+
Let \tcode{\exposid{CONVERT_TO_LVALUE}<C>(E)} be defined
4855+
as in \ref{concepts.compare.general}.
48504856
\tcode{T}, \tcode{U}, and \tcode{Cat}
48514857
model \tcode{\libconcept{three_way_comparable_with}<T, U, Cat>} only if:
48524858
\begin{itemize}
@@ -4859,7 +4865,8 @@
48594865
\item
48604866
\tcode{(t <=> u != 0) == bool(t != u)} is \tcode{true},
48614867
\item
4862-
\tcode{Cat(t <=> u) == Cat(C(t) <=> C(u))} is \tcode{true},
4868+
\tcode{Cat(t <=> u) == Cat(\exposid{CONVERT_TO_LVALUE}<C>(t2) <=>
4869+
\exposid{CONVERT_TO_LVALUE}<C>(u2))} is \tcode{true},
48634870
\item
48644871
\tcode{(t <=> u < 0) == bool(t < u)} is \tcode{true},
48654872
\item

0 commit comments

Comments
 (0)