14

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

rozina
  • 4,120
  • 27
  • 49
  • 3
    You can move it, 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. – Melkon Sep 21 '15 at 08:21
  • @Melko If you make your comment an answer, I can accept it :) – rozina Sep 21 '15 at 08:57

2 Answers2

12

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

Community
  • 1
  • 1
Marco A.
  • 43,032
  • 26
  • 132
  • 246
7

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.

Melkon
  • 418
  • 3
  • 12