Considering this code:
template <class T>
void f(T p) { //(1)
cout << "Second" << endl;
}
template <>
void f(int *p) { //(2)
cout << "Third" << endl;
}
template <class T>
void f(T* p) { //(3)
cout << "First" << endl;
}
A call such as int *p; f(p);
will output First
.
If the order of the declarations is changed, like this:
template <class T>
void f(T* p) { //(3)
cout << "First" << endl;
}
template <class T>
void f(T p) { //(1)
cout << "Second" << endl;
}
template <>
void f(int *p) { //(2)
cout << "Third" << endl;
}
the same call (int *p; f(p);
) will output Third
.
I read about the way in which function template overload resolution takes places: first the resolution considers only non-template functions and the underlying base templates. After the "most specialized" one is chosen, if it is a template function and it has a specialization for the parameters which were deduced (or explicitly specified), that specialization is called.
Now my question is: how it is decided for which underlying base template a function is a specialization? In my example, for which function template overload ( (1) or (3) ) is (2) a specialization?
My guess is that when a specialization is declared, the templates already declared are considered, and from those the most "specialized" (whose parameters are "closest" to this specialization) is chosen. Is this correct? Also, could you point me to where this is specified in the standard?
It prints "First" because the order of declaration affects which template you in fact specialize.
Your example has two function templates, which overload the same name. In the first case, you specialize void f(T p)
, because it's the only template seen so far.
In the second case, it's void f(T* p)
that's specialized. So yes, your guess is correct. The specifics are at [temp.deduct.decl/1]:
In a declaration whose declarator-id refers to a specialization of a function template, template argument deduction is performed to identify the specialization to which the declaration refers. Specifically, this is done for explicit instantiations, explicit specializations, and certain friend declarations. [...]
And that includes the partial ordering of the function templates. However, partial ordering only applies to the available function template declarations at the point you introduce your specialization.
And the standard warns at [temp.expl.spec/7]:
The placement of explicit specialization declarations for function templates, [...] , can affect whether a program is well-formed according to the relative positioning of the explicit specialization declarations and their points of instantiation in the translation unit as specified above and below. When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.