This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
reference_wrapper comparisons are not SFINAE-friendlySection: 22.10.6.6 [refwrap.comparisons] Status: WP Submitter: Jonathan Wakely Opened: 2024-04-19 Last modified: 2024-07-08
Priority: Not Prioritized
View all issues with WP status.
Discussion:
P2944R3 added these hidden friends to reference_wrapper:
friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper);
friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, const T&);
friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper<const T>);
These functions are not templates, and so their declarations are ill-formed for any type that does have any comparison operators, e.g.
struct A { } a;
std::reference_wrapper<A> r(a);
Instantiating reference_wrapper<A> will instantiate
the declarations of the hidden friends, which will attempt to determine the
return types of the operator<=> functions.
That fails because synth-three-way is constrained
and can't be called with arguments of type A.
This can be solved by changing those functions into templates, so they aren't instantiated eagerly, e.g.,
friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper);
or by giving them a deduced return type (so that it isn't instantiated eagerly)
and constraining them to only be callable when valid:
friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper x, reference_wrapper y)
The second alternative is used in the proposed resolution.
In practice the requires-clause can be implemented more simply (and efficiently) by checking the constraints of synth-three-way directly:
requires (const T t) { { t < t } -> boolean-testable; }
but when specified in prose in a Constraints: element it seems
clearer to just use synth-three-way(x.get(), y.get()).
The proposed resolution has been committed to libstdc++'s master branch.
[2024-05-08; Reflector poll]
Set status to Tentatively Ready after eight votes in favour during reflector poll.
[St. Louis 2024-06-29; Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4981.
Modify 22.10.6.1 [refwrap.general] as indicated:
// [refwrap.comparisons], comparisons friend constexpr bool operator==(reference_wrapper, reference_wrapper); friend constexpr bool operator==(reference_wrapper, const T&); friend constexpr bool operator==(reference_wrapper, reference_wrapper<const T>); friend constexprsynth-three-way-result<T>operator<=>(reference_wrapper, reference_wrapper); friend constexprsynth-three-way-result<T>operator<=>(reference_wrapper, const T&); friend constexprsynth-three-way-result<T>operator<=>(reference_wrapper, reference_wrapper<const T>);
Modify 22.10.6.6 [refwrap.comparisons] as indicated:
friend constexprsynth-three-way-result<T>operator<=>(reference_wrapper x, reference_wrapper y);
-7- Returns:
synth-three-way(x.get(), y.get()).friend constexprsynth-three-way-result<T>operator<=>(reference_wrapper x, const T& y);
-8- Returns:
synth-three-way(x.get(), y).friend constexprsynth-three-way-result<T>operator<=>(reference_wrapper x, reference_wrapper<const T> y);-9- Constraints:
is_const_v<T>isfalse.-10- Returns:
synth-three-way(x.get(), y.get()).