https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93480
--- Comment #2 from Will Wray <wjwray at gmail dot com> --- For reference, here's a macro-free workaround to provide portable operator<=> for templated classes with array members, defaulting where possible (current Clang and MSVC) otherwise dispatching to a user-defined implementation (current gcc) https://godbolt.org/z/qbEfh7 First, a trait to check default 3-way array compare: inline constexpr bool has_default_array_compare = [] { struct C { char c[1]; auto operator<=>(C const&) const = default; }; return std::three_way_comparable<C>; }(); Then constrain the operator<=> definitions template <typename T, int N> struct array { T data[N]; friend auto operator<=>(array const&, array const&) requires has_default_array_compare = default; friend constexpr auto operator<=>(array const& l, array const& r) requires (!has_default_array_compare) { return compare_three_way{}(l.data,r.data); } }; However, this only works for templated classes as it is not (yet) allowed to constrain non-template functions.