c++c++23std-expected

Why std::expected's `operator==` is not SFINAE-friendly?


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.


Solution

  • 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.