https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102995
--- Comment #2 from Andrew Pinski <pinskia at gcc dot gnu.org> --- This works correctly on all compilers to do what you want it to do: template<typename A, typename B> class First { public: First() = default; private: int GetId() const { return 1; } template<typename U, typename V, typename D> friend bool operator==(const First<U, V>& lhs, const First<D, V>& rhs); }; template<typename U, typename V, typename D> bool operator==(const First<U, V>& lhs, const First<D, V>& rhs) { return lhs.GetId() == rhs.GetId(); } int main() { First<int, bool> a; First<void *, bool> b; return a == b; } Because you need the operator I suspect the original testcase is invalid code and clang is incorrect in accepting it.