Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is const rvalue reference implicitly converted into const reference?

Tags:

c++

#include <iostream>
using namespace std;

class foo {
public:
    foo() {}
    foo(const foo& other) {cout << "foo's copy constructor " << endl;}
    foo(foo&& other) {cout << "foo's move constructor " << endl;}
    foo(const foo&& other) {cout << "foo's move constructor with const ref ref" << endl;}
};

class bar {
public:
    bar(const foo& f) : f_(move(f)) {}
    foo f_;
};

int main()
{
    foo f;
    bar b(f);
}

In the above code, in absence of the move constructor -- foo(const foo&& other), the rvalue reference move(f) is implicitly converted into a const reference and thus foo's copy constructor is called.

My question is why a const rvalue reference implicitly converted into a const reference instead of a compiler error? Specifically, if I comment out the last move constructor, then foo's copy constructor is called.

like image 325
bigdata2 Avatar asked Dec 06 '25 07:12

bigdata2


1 Answers

Some simpler code with the same reference binding:

int main()
{
    const foo f;
    const foo&  g = std::move(f);
    const foo&& h = std::move(f);
}

The expression std::move(f) is best described as an xvalue of type const foo.

So we have a reference being initialized by an xvalue of type const foo.

Both of g and h are legal and the reference binds directly. const foo&& can only bind to an rvalue, but const foo& can bind to both lvalues and rvalues. (An xvalue is an rvalue).

There is no implicit conversion as suggested in the title, the reference binds directly to the object designated by the initializer.


In the posted code there is overload resolution between two constructors with the same binding as g and h in my example. Overload resolution selects parameter type const foo&& as a better match than const foo& to an argument of type const foo and category "xvalue", since there is a ranking rule that rvalue arguments prefer rvalue references if all else is equal.

But if you remove either of those two constructors then the other one will be selected.

like image 178
M.M Avatar answered Dec 12 '25 15:12

M.M