I was reading about template type deduction in Effective Modern C++ and I think I understand how the compiler determines if a template matches, and what the deduced type should be, but I don't understand how the compiler chooses between matching overloads.
Consider this example:
#include <iostream>
template <typename T>
void hello(T& a) {
std::cout << "Hello World 1" << std::endl;
}
template <typename T>
void hello(const T& a) {
std::cout << "Hello World 2" << std::endl;
}
int main() {
int x = 6;
const int y = 5;
int& z = x;
hello(x);
hello(y);
hello(z);
}
This gives the following output:
Hello World 1
Hello World 2
Hello World 1
Intuitively I can see that the compiler selected the const
overload when the input value was const
which seems to make sense, but I was expecting it to throw an error due to the ambiguity. In particular, if we remove either version of the hello
function the code still compiles and all the calls use the other one. This implies that the compiler has some way of selecting which template is preferable in this scenario to avoid the ambiguity.
I found this excellent explanation What is the partial ordering procedure in template deduction, but I am confused applying it to this scenario. In particular following the process outlined in the answer to that question implies that there is an ordering on the templates themselves which determines which one is "more specialised" and therefore will always be favoured, no matter the input argument. This is at odds with the fact that in my example the compiler made 2 different choices depending on the input type.
First template's function void(int&)
can be matched against void(const int&)
, but not other way around, therefore it's more specialized so for hello(x)
it's the favorite choice.
For same reason void(const int&)
is the only match for hello(y)
.
The call hello(z)
is no different from hello(x)
in this context. Reference would be "discarded".