Why does C++ give preference to rvalue reference over const reference while function call?

392 Views Asked by At

So I wrote a code in C++ 11

#include <iostream>
using namespace std;

void print (int &&a)
{
    cout<<"rval ref";
}

void print (const int& a)
{
    cout<<"const ref";
}

int main()
{
    print(9);   
}

The output of code was fascinating that it is "rval refernce" But if I rewrite the code just removing a function defination:

#include <iostream>
using namespace std;

void print (const int& a)
{
    cout<<"const ref";
}

int main()
{
    print(9);   
}

I get output as "const ref"

Edit: There's one more thing here if I rewrite code again as

#include <iostream>
using namespace std;

void print (int &&a)
{
    cout<<"rval ref";
}

void print (const int&& a)
{
    cout<<"const ref";
}

int main()
{
    print(9);   
}

Still its printing "rval ref" , please explain the logic

Can someone explain why C++ give preference to && over const while passing a ravlue as argument ?## Heading ##

1

There are 1 best solutions below

2
On

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.