I am trying to understand the overload resolution rules in the following case:
template<typename T>
void f(const T& x) {
std::cout << __PRETTY_FUNCTION__ << std::endl; //-
}
template<typename T>
void f(T& x) { // <> Überladung Variante 2
std::cout << __PRETTY_FUNCTION__ << std::endl; //-
}
int main()
{
int e1 = 0;
f(e1);
const int e2 = 0;
f(e2);
}
The output is:
void f(T &) [T = int]
void f(const T &) [T = int]
As I understand in the first call to f(e1)
leads to the viable functions
void f(const int&)
void f(int&)
from which the first one is chosen because the const-qualification hasn't to be removed.
The second call to f(e2)
leads to the type deductions / viable functions
void f(const int&); // T -> int from first template overload
void f(const int&); // T -> const int from second overload
and the output shows that the first overload is choosen.
But why?
When performing type deduction with references, the const
-ness (more specifically CV-ness) is not removed. So in your case the compiler has 2 overloads to choose from:
void f(const T &)
void f(T &)
The compiler then performs "pattern matching" when choosing the overload for your const int e2 = 0;
argument. The first const
overload is a better match (more specialized), as the second one would require deducing T
as const int
, which adds something (i.e. const
-ness).
The rules for template type deductions are not super straightforward, so if you want to learn all nitty-gritty details about templates, I highly recommend the book
C++ Templates: The Complete Guide by David Vandevoorde and Nicolai M. Josuttis.
It's pre C++11, but nevertheless it tells you everything you can think of.
PS: you must make a differentiation between instantiation and template type deduction. The type deduction happens first, then an instantiation follows. So in your case you don't have 2 ambiguous instantiations as you may have thought initially.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With