Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the difference in the flow of universal reference and rvalue reference

Working from the Efficient Modern C++, Item 25. we have an example

Case 1

class Widget {
public:
template<typename T>
void setName(T&& newName)
{ name = std::forward<T>(newName); }
...
};

Case 2

class Widget {
public:
void setName(const std::string& newName)
{ name = newName; }
void setName(std::string&& newName)
{ name = std::move(newName); }
...
};

The call

Widget w;
w.setName("Adela Novak");

Now assuming case 1, the book states that the literal is conveyed to the assignment operator for t std::string inside w's name data member.

Assuming case 2, the book states that -> first a temporary is created from the literal, calling the string constructor, so the setName parameter can bind to it, and than this temporary is moved into w's name data member.

Question

Why does this difference in behavior come about and how am I to think about it?

Namely, why is there no need for a temporary in case 1? Why is there difference? Is T&& not deduced to be an rvalue reference to a string, thus arriving at the same behavior as case 2 (obviously not, as per the book, but why)?

like image 719
LeastSquaresWonderer Avatar asked Jan 02 '23 21:01

LeastSquaresWonderer


1 Answers

In case 1, T is deduced to be const char (&)[12], not std::string. There is no reason for the compiler to promote the string literal to std::string yet. In case 2, every overload requires takes a reference to an std::string, which forces the creation of a temporary std::string to which a reference can be bound using the implicit const char* constructor.

Note that while an rvalue reference such as std::string && may only bind to an rvalue, the templated equivalent T && may bind to both rvalues and lvalues.

like image 105
François Andrieux Avatar answered Jan 05 '23 19:01

François Andrieux