Created on 2025-08-24.00:00:00 last changed 7 days ago
Proposed resolution:
This wording is relative to N5014.
[Drafting note:: We introduce the exposition-only function FUN below to mimic the implicit conversion to `bool`. As a drive-by effect this helps us simplifying (and clarifying, see LWG 484) the existing Mandates element.
Please note that the seemingly unresolved `T` in the `requires` expression below names the first template parameter of the `indirect` class template. ]
Modify [indirect.relops] as indicated:
template<class U, class AA> constexpr bool operator==(const indirect& lhs, const indirect<U, AA>& rhs) noexcept(noexcept(*lhs == *rhs)see below);-?- Let FUN denote the exposition-only function
bool FUN(bool) noexcept;-1- Mandates: The expression FUN(*lhs == *rhs) is well-formed
-2- Returns: If `lhs` is valueless or `rhs` is valueless, `lhs.valueless_after_move() == rhs.valueless_after_move()`; otherwise `*lhs == *rhs`. -?- Remarks: The exception specification is equivalent to:and its result is convertible to `bool`.requires (const T& lhs, const U& rhs) { { FUN(lhs == rhs) } noexcept; }
Modify [indirect.comp.with.t] as indicated:
template<class U> constexpr bool operator==(const indirect& lhs, const U& rhs) noexcept(noexcept(*lhs == rhs)see below);-?- Let FUN denote the exposition-only function
bool FUN(bool) noexcept;-1- Mandates: The expression FUN(*lhs == rhs) is well-formed
-2- Returns: If `lhs` is valueless, `false`; otherwise `*lhs == rhs`. -?- Remarks: The exception specification is equivalent to:and its result is convertible to `bool`.requires (const T& lhs, const U& rhs) { { FUN(lhs == rhs) } noexcept; }
`std::indirect`'s `operator== intentionally uses Mandates instead of Constraints to support incomplete types. However, its function signature has the following `noexcept` specification:
template<class U, class AA> constexpr bool operator==(const indirect& lhs, const indirect<U, AA>& rhs) noexcept(noexcept(*lhs == *rhs));
That is, we check whether the expression `*lhs == *rhs` throws, which unfortunately leads to the following hard error:
struct Incomplete;
static_assert(std::equality_comparable<std::indirect<Incomplete>>);
// hard error, no match for 'operator==' (operand types are 'const Incomplete' and 'const Incomplete')
This makes `operator==` not SFINAE-friendly for incomplete types, which defeats the purpose.
Also, checking `noexcept(*lhs == *rhs)` seems insufficient because the result of `*lhs == *rhs` might still throw during conversion to `bool`.History | |||
---|---|---|---|
Date | User | Action | Args |
2025-08-24 17:30:44 | admin | set | messages: + msg14956 |
2025-08-24 00:00:00 | admin | create |