1

See the piece of code below(notice that s is a array with char instead of string):

#include <string>
#include <iostream>
#include <utility>

void func(std::string & s, char a) {
  std::cout << "here1" << std::endl;
  // ...
}

void func(std::string && s, char a) {
  std::cout << "here2" << std::endl;
  // ...
}

template <class T>
void foo(T && s) {
  std::cout << "foo2" << std::endl;
  func(s, ':');
  //func(std::forward<T>(s), ':');
}

int main(int agrc, char *argv[])
{
  //std::string s("a:b:c:d");
  char s[8] = "abcdefg";
  foo(std::move(s));
  std::string s2("abcd")
  foo(s2);
  return 0;  
}

If I replace func(s, ':') using std::forward, it makes no difference, the foo function will do the prefect forwarding without std::forward in this case.

Is there mis-understanding of 'prefect forwarding' with std::forward in C++11?

xunzhang
  • 2,838
  • 6
  • 27
  • 44

2 Answers2

5

It makes a difference. In your case func(s, ':') will only ever call the overload of func that takes reference to a std::string.

The issue is that named variables and parameters are lvalues themselves and this is also the reason why std::forward exists in the first place.

In your example it has the appearance that the right overload is chosen for the first call to foo even if you don't use std::forward. This is just because you actually call foo with a char[] argument which is used to implicitly construct a temporary of std::string.

pmr
  • 58,701
  • 10
  • 113
  • 156
  • 2
    @xunzhang Your example is bad. Because in the first case `foo` uses an array type and constructs a temporary at the call site. This is why you believe the right overload is chosen. I fixed your example: http://ideone.com/btZd7Y – pmr Jan 19 '14 at 17:42
1

Lets consider first case foo(std::move(s)). Inside of foo, s will be bind to rvalue. But since it has a name (s) it's not an rvalue anymore. So when you pass s to func it will be like passing lvalue to it - it will trigger here1 version. But if you will pass s via std::forward it will be rvalue once again.

In second case s is lvalue reference when foo is entered, so it doesn't change anything whether you pass it directly or via std::forward. You would need to use std::move to get rvalue out of s again.

tumdum
  • 1,981
  • 14
  • 19