Issue 4366: Heterogeneous comparison of expected may be ill-formed (original) (raw)
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.
4366. Heterogeneous comparison of expected may be ill-formed
Section: 22.8.6.8 [expected.object.eq], 22.8.7.8 [expected.void.eq] Status: WP Submitter: Hewill Kang Opened: 2025-09-06 Last modified: 2025-11-11
Priority: Not Prioritized
View all issues with WP status.
Discussion:
These comparison functions all explicitly static_cast the result of the underlying comparison tobool. However, the Constraints only require the implicit conversion, not the explicit one (i.e., "convertible to bool" rather than "models _boolean-testable_").
This means that in some pathological cases it will lead to hard errors (demo):
#include
struct E1 {}; struct E2 {};
struct Bool { operator bool() const; explicit operator bool() = delete; }; Bool operator==(E1, E2);
int main() { std::unexpected e1{E1{}}; std::unexpected e2{E2{}}; return std::expected<int, E1>{e1} == e2; // fire }
It is reasonable to specify return consistency with actual Constraints.
[2025-10-16; Reflector poll]
Set status to Tentatively Ready after five votes in favour during reflector poll.
Related to LWG 4366(i), but the wording styles are inconsistent.optional uses "Effects: Equivalent to ..." and expected just uses_Returns_:.
[Kona 2025-11-08; Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N5014.
- Modify 22.8.6.8 [expected.object.eq] as indicated:
template friend constexpr bool operator==(const expected& x, const T2& v);
-3- Constraints:
T2is not a specialization ofexpected. The expression*x == vis well-formed and its result is convertible tobool.[Note 1:
Tneed not be Cpp17EqualityComparable. — _end note_]-4- Returns: If
x.has_value()istrue,~~&& static_cast<bool>(~~*x == v~~)~~; otherwisefalse.template friend constexpr bool operator==(const expected& x, const unexpected& e);
-5- Constraints: The expression
x.error() == e.error()is well-formed and its result is convertible tobool.-6- Returns: If
!x.has_value()istrue,~~&& static_cast<bool>(~~x.error() == e.error()~~)~~; otherwisefalse. - Modify 22.8.7.8 [expected.void.eq] as indicated:
template<class T2, class E2> requires is_void_v
friend constexpr bool operator==(const expected& x, const expected<T2, E2>& y);-1- Constraints: The expression
x.error() == y.error()is well-formed and its result is convertible tobool.-2- Returns: If
x.has_value()does not equaly.has_value(),false; otherwise ifx.has_value()istrue,true; otherwise~~|| static_cast<bool>(~~x.error() == y.error()~~)~~.template
friend constexpr bool operator==(const expected& x, const unexpected& e);-3- Constraints: The expression
x.error() == e.error()is well-formed and its result is convertible tobool.-4- Returns: If
!x.has_value()istrue,~~&& static_cast<bool>(~~x.error() == e.error()~~)~~; otherwisefalse.