My code:
#include <string>
#include <utility>
#include <iostream>
void store(std::string & val)
{
std::cout << "lvalue " << val << '\n';
}
void store(std::string && val)
{
std::cout << "rvalue " << val << '\n';
}
template<typename T> void print(T && val)
{
std::cout << std::boolalpha << std::is_lvalue_reference<T>::value << " ";
store(std::forward<T>(val));
}
int main()
{
std::string val("something");
print(val);
print("something else");
}
my output:
true lvalue something
true rvalue something else
I've read on Universal referencing and understand why T is a lvalue when the input is a lvalue but I don't understand how is T a lvalue when the input is a rvalue, how does that collapse to the right paramter?
I don't understand how is T a lvalue when the input is a rvalue, how does that collapse to the right paramter?
No, the input is not an rvalue.
String literals are lvalues, and that's what you pass as a parameter to the function. That's why "true" is printed.
Now, recall that string literals cannot be modified (String Literals).
So, "something else" is of lenght 14 + 1 (for the null terminator), thus a const char[15]
.
Now, since string literals cannot be modified, the reference will be deduced as:
const char(&)[15];
The prototype of your method is:
store(std::string && val)
which creates a temporary std::string
from const char
.