operator<=>(optional<T>, U)
Section: 22.5.8 [optional.comp.with.t] Status: C++23 Submitter: Casey Carter Opened: 2021-06-07 Last modified: 2023-11-22
Priority: Not Prioritized
View all other issues in [optional.comp.with.t].
View all issues with C++23 status.
Discussion:
The three-way-comparison operator for optionals and non-optionals is defined in [optional.comp.with.t] paragraph 25:
template<class T, three_way_comparable_with<T> U> constexpr compare_three_way_result_t<T, U> operator<=>(const optional<T>& x, const U& v);-25- Effects: Equivalent to:
return bool(x) ? *x <=> v : strong_ordering::less;
Checking three_way_comparable_with
in particular requires checking that x < v
is well-formed
for an lvalue const optional<T>
and lvalue const U
. x < v
can be rewritten as
(v <=> x) > 0
. If U
is a specialization of optional
, this overload could be used for
v <=> x
, but first we must check the constraints…
The straightforward fix for this recursion seems to be to refuse to check three_way_comparable_with<T>
when U
is a specialization of optional
. MSVC has been shipping such a fix; our initial tests for
this new operator triggered the recursion.
Previous resolution [SUPERSEDED]:
This wording is relative to N4885.
Modify 22.5.2 [optional.syn], header
<optional>
synopsis, as indicated:[…] // 22.5.8 [optional.comp.with.t], comparison with T […] template<class T, class U> constexpr bool operator>=(const optional<T>&, const U&); template<class T, class U> constexpr bool operator>=(const T&, const optional<U>&); template<class T,three_way_comparable_with<T>class U> requires see below constexpr compare_three_way_result_t<T, U> operator<=>(const optional<T>&, const U&); […]Modify 22.5.8 [optional.comp.with.t] as indicated:
template<class T,three_way_comparable_with<T>class U> requires (!is-specialization-of<U, optional>) && three_way_comparable_with<T, U> constexpr compare_three_way_result_t<T, U> operator<=>(const optional<T>&, const U&);-?- The exposition-only trait template
-25- Effects: Equivalent to:is-specialization-of<A, B>
is a constant expression with valuetrue
whenA
denotes a specialization of the class templateB
, andfalse
otherwise.return bool(x) ? *x <=> v : strong_ordering::less;
[2021-06-14; Improved proposed wording based on reflector discussion]
[2021-06-23; Reflector poll]
Set status to Tentatively Ready after five votes in favour during reflector poll.
[2021-10-14 Approved at October 2021 virtual plenary. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4885.
Modify 22.5.2 [optional.syn], header <optional>
synopsis, as indicated:
[…] // 22.5.3 [optional.optional], class template optional template<class T> class optional; template<class T> constexpr bool is-optional = false; // exposition only template<class T> constexpr bool is-optional<optional<T>> = true; // exposition only […] // 22.5.8 [optional.comp.with.t], comparison with T […] template<class T, class U> constexpr bool operator>=(const optional<T>&, const U&); template<class T, class U> constexpr bool operator>=(const T&, const optional<U>&); template<class T,three_way_comparable_with<T>class U> requires (!is-optional<U>) && three_way_comparable_with<T, U> constexpr compare_three_way_result_t<T, U> operator<=>(const optional<T>&, const U&); […]
Modify 22.5.8 [optional.comp.with.t] as indicated:
template<class T,three_way_comparable_with<T>class U> requires (!is-optional<U>) && three_way_comparable_with<T, U> constexpr compare_three_way_result_t<T, U> operator<=>(const optional<T>& x, const U& v);-25- Effects: Equivalent to:
return bool(x) ? *x <=> v : strong_ordering::less;