Search code examples
c++rvalue-referenceforwarding-reference

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)?


Solution

  • 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.