In addition to not being able to ship binary frameworks the fundamental flaw with the C++ model is that type checking happening after template expansion is not really amenable to good tooling or diagnostics. Say you have something like
func foo<T>(t: T) {
t.bar(123)
}
With the C++ model, the type signature of foo() doesn't describe the fact that it expects T to have an instance method named bar which can take an integer (or something expressible by an integer literal). When I invoke foo() with some specific concrete type, I expand the template and only then do I look up the definition of bar() on this type. It might take an Int, or it might take a String, or it might not exist at all. In the latter two cases, the error message at the call site will point inside the template expansion. This is simply unworkable for complex templates and leads to unusable error messages where it is not really clear what the source of the error is. By enforcing generic requirements as part of the function's type, Swift is able to separately type check the body of foo() and the caller, which is really much better.