Using a hierarchy to show template errors is brilliant and I'm sort of surprised compilers haven't always done that. I was investigating C++-style templates for a hobby language of mine and SFINAE is an important property to make them work in realistic codebases, but leads to exactly this problem. When a compile error occurs, there isn't a single cause, or even a linear chain of causes, but an potentially arbitrarily…
I really wish templates didn't work on a dumb "replace at call site until something compiles" manner. All template requirements should be verified at the function definition, not at every call site. There is concepts. But they are so unwieldy.
Yes, it's definitely nice to be able to typecheck generic code before instantiation. But supporting that ends up adding a lot of complexity to the typesystem.
C++-style templates are sort of like "compile-time dynamic types" where the type system is much simpler because you can just write templates that try to do stuff and if the instantiation works, it works.
C++ templates are more powerful than generics in most other languages, while not having to deal with covariance/contravariance, bounded quantification, F-bounded quantification, traits, and all sorts of other complex machinery that Java, C#, etc. have.
I still generally prefer languages that do the type-checking before instantiation, but I think C++ picks a really interesting point in the design space.