I'm reading the documentation on std::expected::operator==
, and apparently it's not SFINAE-friendly. Instead of "doesn't participate in overload resolution if [types are not eq-comparable]", it says "the program is ill-formed [in that case]".
And indeed:
#include <concepts>
#include <expected>
struct A {};
static_assert(!std::equality_comparable<std::expected<A, A>>);
This assertion fails on MSVC and Clang with libc++, and causes a hard error on Clang with MSVC STL.
But why is it not SFINAE-friendly?
std::expected<T,U>
requires both T
and U
to be complete anyway, so seemingly nothing is stopping all operations on it to be SFINAE-friendly.
I think it was simply overlooked.
Until April 2024 the operator==
of similar library types like std::pair
, std::tuple
, std::optional
, std::variant
etc. were also not SFINAE-friendly in this sense either.
They were made SFINAE-friendly with P2944R3 which also notes that this probably just happened without any intention behind it.
The wording changes are listed in the paper starting from here. If a clause originally said "Mandates:" that means that if the condition was not satisfied the program was ill-formed (i.e. a hard error). If it originally said "Preconditions:" then not satisfying the condition caused the program to have undefined behavior. When it now says "Constraints:" instead, then not satisfying the condition means that the overload does not participate in overload resolution (i.e. it is SFINAE-friendly).
My guess would be that std::expected
was similarly forgotten.