Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Appropriate way to forward rvalue reference

I have the following code:

#include <iostream>
#include <string>

using std::cout;
using std::endl;

void bar(const std::string& str)
{
    cout << "const str - " << str << endl;
}

void bar(std::string&& str)
{
    cout << "str - " << str << endl;
}

void foo(std::string&& str)
{
    bar(str);
}


int main()
{
    foo("Hello World");
}

In the above code the void bar(const std::string& str) overload gets called. If I want the void bar(std::string&& str) overload to be called I either have to write bar(std::move(str)); or bar(std::forward<std::string>(str));

Obviously the forward code is longer, but it makes more sense to me. My question is what is more commonly used and prefered. Writing bar(std::forward(str)); would be the best solution imo, but that is not an option :)

like image 633
rozina Avatar asked Sep 21 '15 08:09

rozina


2 Answers

Citing from Effective Modern C++

From a purely technical perspective, the answer is yes: std::forward can do it all. std::move isn’t necessary. Of course, neither function is really necessary, because we could write casts everywhere, but I hope we agree that that would be,well, yucky. std::move’s attractions are convenience, reduced likelihood of error, and greater clarity.

Using std::move here

void foo(std::string&& str)
{
    bar(str);
}

will return str as an rvalue reference (which is exactly what you're trying to achieve) while using std::forward would return either an lvalue reference (which you're not interested in) or an rvalue reference (thus equivalent in this case to std::move). Obviously using none would just keep calling the const std::string& str one since str is an lvalue in that function.

Bottom-line: they would do the same thing but using std::move is preferred since

  • It avoids explicitly specifying template arguments
  • It is more idiomatic
  • It goes straight to the point: std::forward is not intended to be used that way (cfr. Universal references) or in that context although it would surely work

I might agree that "I'm forwarding this rvalue reference to the other function" might make sense as a standalone sentence but it kind of misses the point of the matter. You could re-wire your brain to think it like "Keep 'moving' this rvalue reference to the other function"

Also possibly related: https://stackoverflow.com/a/18214825/1938163

like image 168
Marco A. Avatar answered Oct 24 '22 16:10

Marco A.


You can move it whenever you are sure it's an rvalue reference.

Forward should be used in templated code when you can't be sure if it's rvalue or lvalue reference. :)

In templated code && mean universal reference, which can be either rvalue or lvalue.

Also note, that std::move is casting it without any check, unlike forward, so while forward is safer if you are not sure what should you do, move is faster.

like image 28
Melkon Avatar answered Oct 24 '22 15:10

Melkon