https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119714
Erik Bråthen Solem <erikbsolem at hotmail dot com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |erikbsolem at hotmail dot com --- Comment #5 from Erik Bråthen Solem <erikbsolem at hotmail dot com> --- So the problematic equality operator is: template< class T2 > friend constexpr bool operator==( const expected& lhs, const T2& val ); In GCC 15’s <expected> header the definition looks like this after the constraints were added: template<typename _Up> requires (!__expected::__is_expected<_Up>) && requires (const _Tp& __t, const _Up& __u) { { __t == __u } -> convertible_to<bool>; } friend constexpr bool operator==(const expected& __x, const _Up& __v) noexcept(noexcept(bool(*__x == __v))) { return __x.has_value() && bool(*__x == __v); } According to cppreference this operator requires that *lhs == val is well-formed, with the exact wording being changed between C++23 and C++26. Perhaps a dumb question, but should it not be { *__t == __u } -> convertible_to<bool>; then, instead of { __t == __u } -> convertible_to<bool>; i.e., with the asterisk? Since it is the contained value of lhs (not the container) that must be comparable to val? I tried the following comparisons: expected<int, int> e = 42; function<expected<int, int>()> fun; fun == nullptr; *e == fun; - GCC 14.2 accepts both comparisons (but the program SEGFAULTs upon execution because *e == fun does not make sense). - GCC 15.1 reports this circular dependency for both. - GCC 15.1 where I manually edited expected as suggested above accepts the first one and rejects the second one, this time with the correct “no match for 'operator=='” message, and the printout shows that the candidate operator in question is skipped with reason “constraints not satisfied” (and not because something depends on itself).