optional
's spaceship with U
with a type derived from optional
causes infinite constraint meta-recursionSection: 22.5.8 [optional.comp.with.t] Status: C++23 Submitter: Ville Voutilainen Opened: 2022-07-25 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:
What ends up happening is that the constraints of
operator<=>(const optional<T>&, const U&)
end up
in three_way_comparable_with
, and then in partially-ordered-with
,
and the expressions there end up performing a conversion from U
to an
optional
, and we end up instantiating the same operator<=>
again, evaluating its constraints again, until the compiler bails out.
U
so that U
is not publicly and unambiguously derived
from a specialization of optional, SFINAEing that candidate out, and letting
22.5.6 [optional.relops]/20 perform the comparison instead.
[2022-08-23; Reflector poll]
Set status to Tentatively Ready after five votes in favour during reflector poll.
[2022-11-12 Approved at November 2022 meeting in Kona. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4910.
[Drafting note: This proposed wording removes the only use of
is-optional
. ]
Modify 22.5.2 [optional.syn], header <optional>
synopsis, as indicated:
[…] namespace std { // 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 onlytemplate<class T> concept is-derived-from-optional = requires(const T& t) { // exposition only []<class U>(const optional<U>&){ }(t); }; […] // 22.5.8 [optional.comp.with.t], comparison with T […] template<class T, class U> constexpr bool operator>=(const T&, const optional<U>&); template<class T, class U> requires (!is-derived-from-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, class U> requires (!is-derived-from-optional<U>) && three_way_comparable_with<T, U> constexpr compare_three_way_result_t<T, U> operator<=>(const optional<T>&, const U&);-25- Effects: Equivalent to:
return x.has_value() ? *x <=> v : strong_ordering::less;