Lets see on case by case basis what is happening:
Case 1
Here we consider:
void print (int &&a)
{
cout<<"rval ref";
}
void print (const int& a)
{
cout<<"const ref";
}
int main()
{
print(9); //chooses print(int&&) version
}
The behavior of this case 1 can be understood from over.ics.rank which states:
3.2 Standard conversion sequence S1
is a better conversion sequence than standard conversion sequence S2
if
S1
and S2
are reference bindings ([dcl.init.ref]) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and S1
binds an rvalue reference to an rvalue and S2
binds an lvalue reference.
(emphasis mine)
This means that in your this case 1, the version with int&&
is preferred over const int&
.
Case 2
Here we consider:
void print (const int& a)
{
cout<<"const ref";
}
int main()
{
print(9); //chooses the only viable and available option print(const int&)
}
Here in case 2, since an lvalue reference to const
object is allowed to bind to an rvalue, the provided print(const int&)
is viable and is the only one available and hence is selected.
Case 3
Here we consider:
void print (int &&a)
{
cout<<"rval ref";
}
void print (const int&& a)
{
cout<<"const ref";
}
int main()
{
print(9);
}
Now, this chooses the first version print(int&&)
because 9
is an int
prvalue and not a const int
prvalue. Note also that for a const int
prvalue, its const
will be stripped off before any further analysis and so the first version print(int&&)
will be selected. This is as specified in expr#6:
If a prvalue initially has the type cv T
, where T
is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T
prior to any further analysis.
This means that for class type const
prvalues the second version of the function print
with print(const C&&)
will be selected unlike the built in type int
as demonstrated below.
struct C
{
C()
{
std::cout<<"default ctor"<<std::endl;
}
};
void print (C &&a)
{
cout<<"rval ref";
}
void print (const C&& a)
{
cout<<"const ref";
}
const C func()
{
const C temp;
return temp;
}
int main()
{
print(func()); //prints const ref
}
The output of the above program for class type C
is:
default ctor
const ref
As is evident from the above example, for class types the second version of print with const C&&
will be selected.