Created on 2024-04-19.00:00:00 last changed 3 weeks ago
Proposed resolution:
This wording is relative to N4981.
Modify [optional.comp.with.t] as indicated:
template<class T, class U> constexpr bool operator==(const optional<T>& x, const U& v);
-1- Constraints: `U` is not a specialization of `optional`. The expression
*x == v
is well-formed and its result is convertible to `bool`.template<class T, class U> constexpr bool operator==(const T& v, const optional<U>& x);
-3- Constraints: `T` is not a specialization of `optional`. The expression
v == *x
is well-formed and its result is convertible to `bool`.template<class T, class U> constexpr bool operator!=(const optional<T>& x, const U& v);
-5- Constraints: `U` is not a specialization of `optional`. The expression
*x != v
is well-formed and its result is convertible to `bool`.template<class T, class U> constexpr bool operator!=(const T& v, const optional<U>& x);
-7- Constraints: `T` is not a specialization of `optional`. The expression
v != *x
is well-formed and its result is convertible to `bool`.template<class T, class U> constexpr bool operator<(const optional<T>& x, const U& v);
-9- Constraints: `U` is not a specialization of `optional`. The expression
*x < v
is well-formed and its result is convertible to `bool`.template<class T, class U> constexpr bool operator<(const T& v, const optional<U>& x);
-11- Constraints: `T` is not a specialization of `optional`. The expression
v < *x
is well-formed and its result is convertible to `bool`.template<class T, class U> constexpr bool operator>(const optional<T>& x, const U& v);
-13- Constraints: `U` is not a specialization of `optional`. The expression
*x > v
is well-formed and its result is convertible to `bool`.template<class T, class U> constexpr bool operator>(const T& v, const optional<U>& x);
-15- Constraints: `T` is not a specialization of `optional`. The expression
v > *x
is well-formed and its result is convertible to `bool`.template<class T, class U> constexpr bool operator<=(const optional<T>& x, const U& v);
-17- Constraints: `U` is not a specialization of `optional`. The expression
*x <= v
is well-formed and its result is convertible to `bool`.template<class T, class U> constexpr bool operator<=(const T& v, const optional<U>& x);
-19- Constraints: `T` is not a specialization of `optional`. The expression
v <= *x
is well-formed and its result is convertible to `bool`.template<class T, class U> constexpr bool operator>=(const optional<T>& x, const U& v);
-21- Constraints: `U` is not a specialization of `optional`. The expression `*x >= v` is well-formed and its result is convertible to `bool`.
template<class T, class U> constexpr bool operator>=(const T& v, const optional<U>& x);
-23- Constraints: `T` is not a specialization of `optional`. The expression
v >= *x
is well-formed and its result is convertible to `bool`.
[ Wrocław 2024-11-23; Status changed: Voting → WP. ]
[ 2024-08-21; Move to Ready at LWG telecon ]
[ 2024-06-24; Reflector poll ]
Set priority to 1 after reflector poll. LWG 3746 changes might be needed here too, i.e, consider types derived from `optional`, not only `optional` itself.
p2944r3 added constraints to `std::optional`'s comparisons, e.g.
-1-template<class T, class U> constexpr bool operator==(const optional<T>& x, const optional<U>& y);
MandatesConstraints: The expression `*x == *y` is well-formed and its result is convertible to `bool`.…
-1-template<class T, class U> constexpr bool operator==(const optional<T>& x, const U& v);
MandatesConstraints: The expression `*x == v` is well-formed and its result is convertible to `bool`.
But I don't think the constraint on the second one (the "compare with value")
is correct. If we try to compare two optionals that can't be compared,
such as optional<void*>
and optional<int>
,
then the first overload is not valid due to the new constraints, and so does
not participate in overload resolution. But that means we now consider the
second overload, but that's ambiguous. We could either use
operator==<void*, optional<int>>
or we could use
operator==<optional<void*>, int>
with the arguments
reversed (using the C++20 default comparison rules).
We never even get as far as checking the new constraints on those overloads,
because they're simply ambiguous.
Before p2944r3 overload resolution always would have selected the first overload, for comparing two optionals. But because that is now constrained away, we consider an overload that should never be used for comparing two optionals. The solution is to add an additional constraint to the "compare with value" overloads so that they won't be used when the "value" is really another optional.
A similar change was made to `optional`'s operator<=>
by
LWG 3566, and modified by LWG 3746.
I haven't analyzed whether we need the modification here too.
The proposed resolution (without `is-derived-from-optional`) has been implemented and tested in libstdc++.
History | |||
---|---|---|---|
Date | User | Action | Args |
2024-11-28 21:40:31 | admin | set | messages: + msg14478 |
2024-11-28 21:40:31 | admin | set | status: voting -> wp |
2024-11-19 16:09:07 | admin | set | status: ready -> voting |
2024-08-21 17:27:00 | admin | set | messages: + msg14335 |
2024-08-21 17:27:00 | admin | set | status: new -> ready |
2024-06-24 12:09:57 | admin | set | messages: + msg14181 |
2024-04-19 17:15:59 | admin | set | messages: + msg14068 |
2024-04-19 00:00:00 | admin | create |