- It gets you really garbage error messages, because the type errors are usually about something in the body of the template, wherever it tries to do something that the type you substituted doesn't support, rather at the offending call site.
- It hurts compile times (above and beyond proper generics), since you need to type check the generic function at every call site, rather than just once.
- It makes it easy to break interfaces, because exactly what is required of a type parameter isn't written down anywhere -- it's just whatever the body tries to do with it.
(Though it is also true that generics are certainly not a full substitute for macros. I would welcome some mechanism for doing codegen that didn't complicate the build system and was a bit lighter weight than what we have now).