Created on 2024-04-19.00:00:00 last changed 4 months ago
Proposed resolution:
This wording is relative to N4981.
Modify [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 constexpr
synth-three-way-result<T>auto operator<=>(reference_wrapper, reference_wrapper); friend constexprsynth-three-way-result<T>auto operator<=>(reference_wrapper, const T&); friend constexprsynth-three-way-result<T>auto operator<=>(reference_wrapper, reference_wrapper<const T>);
Modify [refwrap.comparisons] as indicated:
friend constexpr
synth-three-way-result<T>auto operator<=>(reference_wrapper x, reference_wrapper y);-?- Constraints: The expression
synth-three-way(x.get(), y.get())
is well-formed.-7- Returns:
synth-three-way(x.get(), y.get())
.friend constexpr
synth-three-way-result<T>auto operator<=>(reference_wrapper x, const T& y);-?- Constraints: The expression
synth-three-way(x.get(), y)
is well-formed.-8- Returns:
synth-three-way(x.get(), y)
.friend constexpr
synth-three-way-result<T>auto operator<=>(reference_wrapper x, reference_wrapper<const T> y);-9- Constraints:
is_const_v<T>
is `false`. The expressionsynth-three-way(x.get(), y.get())
is well-formed.-10- Returns:
synth-three-way(x.get(), y.get())
.
[ St. Louis 2024-06-29; Status changed: Voting → WP. ]
[ 2024-05-08; Reflector poll ]
Set status to Tentatively Ready after eight votes in favour during reflector poll.
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.,
template<class U = T>
friend constexpr synth-three-way-result<TU> 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>auto operator<=>(reference_wrapper x, reference_wrapper y)
requires requires (const T t) { synth-three-way(t, t); }
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.
History | |||
---|---|---|---|
Date | User | Action | Args |
2024-07-08 09:00:03 | admin | set | messages: + msg14239 |
2024-07-08 09:00:03 | admin | set | status: voting -> wp |
2024-06-24 13:01:55 | admin | set | status: ready -> voting |
2024-05-08 10:36:29 | admin | set | messages: + msg14121 |
2024-05-08 10:36:29 | admin | set | status: new -> ready |
2024-04-19 16:34:31 | admin | set | messages: + msg14066 |
2024-04-19 00:00:00 | admin | create |