https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102396
--- Comment #5 from Patrick Palka <ppalka at gcc dot gnu.org> --- (In reply to Giuseppe D'Angelo from comment #3) > Hello Patrick, > > Thank you for the insights. I'm left wondering however if the CWG resolution > would possibly ever allow the operator== to be defined as a hidden friend; > the workaround you mentioned may lead to redefinition errors (as now it > doesn't depend on S any more)? Ah yeah, I ran into a similar issue when implementing the pipe operator for range adaptor closures in libstdc++... IIRC, I worked around this by introducing a non-template base class and defining the hidden template friend in the base class instead. So something like: #include <type_traits> #include <concepts> template <typename T> class S; template <typename T> static inline std::true_type is_S_impl(const S<T>&); static inline std::false_type is_S_impl(...); template <typename T> concept is_S = decltype(is_S_impl(std::declval<T>()))::value; template <typename T> struct S; struct S_Base { template <typename V, typename U> requires is_S<V> && (!is_S<U>) && std::equality_comparable_with<typename V::type, U> friend bool operator==(const V &v, const U &u) { return v.data == u; } }; template <typename T> struct S : private S_Base { using type = T; T data; S(); explicit S(const T &); }; void f() { S<int> s1; s1 == 123; S<double> s2; s2 == 123.4; }