difference between rvalue reference and lvalue reference as argument
The first option can take lvalues because it's an lvalue reference. It can take rvalues because it is marked const
and rvalues are allowed to bind to const
lvalue references.
The second version is only allowed non-const
rvalues because you can't implicitly strip const
from the referencee and rvalue references don't allow lvalues to bind to them.
The semantic difference is that the former function is saying "I am just going to read what you pass in here and I'd rather not copy it", whereas the latter is saying "I reserve the right to rip the guts out of this object and paint my living room with them".
Only constant lvalue references may be bound to temporary objects.
So this function
void printReference (const string& str)
{
cout << str;
}
may be called for the following objects:
const std::string s1( "constant lvalue" );
printReference( s1 );
std::string s2( "non-constant lvalue" );
printReference( s2 );
printReference( "A temporary object of type std::string" );
printReference( static_cast<const std::string>( "A temporary object of type std::string" ) );
As for this function
void printReference (string&& str)
{
cout << str;
}
among the above mentioned objects you may call it only for a non-constant rvalue.
printReference( "A temporary object of type std::string" );
You may not call it like
printReference( static_cast<const std::string>( "A temporary object of type std::string" ) );
due to the presence of the const qualifier.
If you will overload the function the following way
void printReference (const string&& str)
^^^^^
{
cout << str;
}
then this call
printReference( static_cast<const std::string>( "A temporary object of type std::string" ) );
will be valid.