10

After reading the post:http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html.

I can not figure out that when you write functions that take lvalue or rvalue references as arguments, such as this:

void printReference (const string& str)
{
    cout << str;
}

void printReference (string&& str)
{
    cout << str;
}

why the first printReference function could accept any argument, whether it be an lvalue or an rvalue, and regardless of whether the lvalue or rvalue is mutable or not. However, in the second printReference function, just allow to pass mutable rvalue.

May be my understanding is wrong, could anyone help me figure out it.

pro-gramer
  • 166
  • 1
  • 3
  • 14
sydridgm
  • 1,012
  • 4
  • 16
  • 30
  • Why? Because the language specification says so. Are you asking for the reason(s) for this? Although I think you're wrong about "mutable rvalue". It doesn't have to be mutable (it could be a literal constant.) – juanchopanza Nov 20 '15 at 14:57
  • @juanchopanza yeah, I have same confuse as yours. The original sentence in the post is `However, in the presence of the second overload, printReference taking an rvalue reference, it will be given all values except mutable rvalue-references.` Do you know what it means? – sydridgm Nov 20 '15 at 15:02
  • That article looks a bit dated. The terms lvalue and rvalue are from C++03 (and earlier). Since C++11we have added a couple more value categories (gl/x/pr) and you should have a passing understanding of them. – Martin York Aug 06 '20 at 00:09

2 Answers2

14

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

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
7

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.

pro-gramer
  • 166
  • 1
  • 3
  • 14
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335