I started out wanting to document implicit function template instantiation (IFTI) and type deduction and ended up reading the DMD frontend code for template instantiation. There I discovered that choosing the correct template declaration involves more logic than the spec indicates.
The specification says that if a template instantiation has an argument list that fits more than one template declaration, the most specialized declaration is chosen. If the declarations are equally specialized or there is no such order, an error is raised. Determining which declaration is more specialized is done in a way inherited from C++: if the first declaration could be instantiated with any argument list that's valid for the second, the first is equally or less specialized than the second. In the DMD frontend though, there's another factor that eliminates some candidates before the ordering criterion is applied: each template declaration matches the template argument list either exactly or with conversions (similar to function overloads). If there is at least one exact match, the most specialized declaration is chosen among the exact matches. Only if there are no exact matches is the ordering criterion used to find the most specialized among the matches-with-conversion. It gets interesting when you throw in the fact that template type parameters without specialization will generally be considered to be match-with- conversion only (a comment states: "so that matches with specializations are better"). For instance template Foo1(T) { pragma(msg, "type"); } template Foo1(alias T) { pragma(msg, "alias"); } alias Foo1!(Object) f1; // alias (type is only match-with-conversions) but template Foo2(T : Object) { pragma(msg, "type"); } template Foo2(alias T) { pragma(msg, "alias"); } alias Foo2!(Object) f2; // type (both match exactly, type is more specialized) (the same works with a tuple parameter instead of the alias parameter). It's easy to see that for value parameters looking at the match quality is a good idea template Bar1(int i) { pragma(msg, "int"); } template Bar1(uint i) { pragma(msg, "uint"); } alias Bar1!(42) b1; // int (uint only matches with conversions) as the template instantiation would be ambiguous otherwise - neither declaration is more specialized than the other. Is this intended behavior? If so, what's the rationale for checking the match quality for non-value parameters? Is there a case where mere template ordering would produce inferior results with type parameters? If it is intended, let's document and explain it in the specification. If it isn't, it needs to be changed or removed before the D2 freeze makes code into law.