This overload resolution behavior baffles me:
#include "stdio.h"
template<class T>
class C
{
public:
C(T v): m(v) {};
T m;
template<class U>
T f(U &&p)
{
printf("rRef called.\n");
return p;
}
template<class U>
T f(const U &p)
{
printf("const Ref called.\n");
return p;
}
};
int main()
{
C<int> a(5);
a.f<int&>(a.m);
a.f(a.m);
return 0;
}
Outputs:
const Ref called.
rRef called.
When debugging in gdb or Visual Studio, both debuggers show
int C<int>::f<int &>() called in both cases, but the explicit template resolution resolves to the expected const ref, while the second resolves to a rvalue reference. Why? Why doesn't the compiler even try
int C<int>::f<int>() which I thought would be the obvious match?
How can a rvalue reference bind to a member value? Isn't a.m a lvalue?
When you make the call:
the compiler has to choose between the following candidates:
For this overload resolution process, first both templates are transformed for the parameter
int&.Substituting
U = int &for#1givesint & &&, which due to reference collapsing, becomesint &.Similarly, substituting
U = int &for#2givesint & const &, which again due to reference collapsing, becomesint &.Now, since both overloads match, partial ordering is used to determine which template to call. Now
U const &is more specialized thanU &&. This is becauseU &&can bind to all the types thatU const &can, but the converse is not true.Hence, since
#2is more specialized, it wins in overload resolution, and gets called.In this call:
the template parameter is not specified. This means the parameter of
#1is considered to be a forwarding reference, and this matches all types that are passed in, and so#1gets called.