7

What are the cases when std::forward is not needed? It is used to wrap inner function argument which is templated-rvalue (that is, it can be lvalue or named-rvalue). Like in:

template<class T>
void outer(T&& t) { 
    inner(std::forward<T>(t)); 
}

I am guessing one case is when inner function parameters are passed by value. Are there other cases? I've got this question when I was writing std::begin(std::forward<Ct>(ct)) where Ct is templated-rvalue-ref.

EDIT about possible duplicate

If I remember correctly, this is 3rd attempt to close this 4yr old question as duplicate by some newbie who don't understand the question.

"Advantages of using forward?" and "When not to use std::forward with r-values?" are very different questions. First is introduction into r-values for beginners and second is discussion of perfect forwarding for advanced C++ user. I am author of meta-template library and lambda library, who don't need verbose description of basics. Information in answer is very different from other question.

Leonid Volnitsky
  • 8,854
  • 5
  • 38
  • 53
  • 3
    Your question is backwards. There are infinitely many cases when std::forward is *not* needed. I think you are really asking for clarification on when to use std::forward exactly. But that question exists already. – D Drmmr Feb 22 '16 at 10:29
  • @DDrmmr -- This is when not to use `std::forward` with r-values. I've added clarification in the title. – Leonid Volnitsky Feb 22 '16 at 12:01
  • @DDrmmr -- just wanted to add to my previous comment. This is about perfect forwarding, not about of r-values basics. – Leonid Volnitsky Feb 22 '16 at 12:12

3 Answers3

6

Perfect forwarding is possible when the template parameter type contains a value category. (If this sentence doesn't make sense, take a minute to familiarize yourself with the problem at hand.)

Given:

template <typename T>
void foo(T&& x); 

Within the body of foo, T will either take the form of U or U&. The former means we were passed an rvalue, the latter means we were passed an lvalue. We can forward this fact on like so:

template <typename T>
void foo(T&& x)
{
    bar(std::forward<T>(x));
}

Pass an lvalue to foo, bar gets the same lvalue. Pass an rvalue to foo, bar gets the rvalue.

If you cannot distinguish a value category, then forwarding is of no use. It's only useful when you have a template parameter that's deduced in the same fashion as above. So yes, it has no use here:

template <typename T>
void foo(const T& x)
{
    // if this was called as foo(1), we're none the wiser
}
Community
  • 1
  • 1
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • @LeonidVolnitsky: I don't understand. Which part is unclear? Do you fully understand what forwarding is? – GManNickG Aug 21 '12 at 15:45
  • I understand what perfect forwarding is. Both of your answers (this one and linked) are very clear and good in explaining basic of forwarding (and both got +1 from me). But unfortunately they do not answer my question. Some types of inner functions do not care what type of valueness argument is. And for them using `std::forward` does not buy anything. In my question I was trying to find all such kinds. – Leonid Volnitsky Aug 21 '12 at 16:13
  • @LeonidVolnitsky: Sorry, I cannot add more because I'm not seeing what you're asking. You seem to understand when forwarding gets you nothing, so just look at the function you'll be calling and see if it will work. – GManNickG Aug 21 '12 at 17:03
3

I am answering to my own question as I didn't get satisfactory answer so far. If I will get even small improvement/addition to this - I will chose your answer as accepted.

In general std::forward will be beneficial with inner function if effect of perfect forwarding will be achieved. Otherwise it is superfluous.

Use std::forward to wrap inner function arg only if any of below is true:

  • inner function parameter is templated-rvalue-ref (now called "forwarding reference");
  • inner function has multiple overloads which differentiate based on parameter r/l-valueness;
  • inner function has multiple overloads which differentiate lvalue parameter based on constness;
Leonid Volnitsky
  • 8,854
  • 5
  • 38
  • 53
  • 2
    This sentence is confusing: "inner function parameter is templated-rvalue-ref" -- when you have a forwarding reference, it is a concept totally distinct from "rvalue-ref", and calling it an rvalue-ref is a source of confusion, even though both of them use `&&` syntax. Maybe the correct answer is, "Use `std::forward` when you are passing a forwarding reference to another function call, and don't use it otherwise"? – Chris Beck Feb 22 '16 at 10:19
  • @ChrisBeck -- Term "forwarding reference" was introduced in 2014. This is question from 2012. Expression "templated rvalue-ref" is "forwarding reference" by definition (per n4164). I will try to reword my answer to make it clearer. – Leonid Volnitsky Feb 22 '16 at 11:52
-1

Use std::forward (on the formal parameter to a templated function, whose type is of the form T&&, T a type parameter of the template):

  • When the inner function call is the last use of the parameter in the outer function, and
  • When possible overloads of the inner function may or may not take the parameter as an rvalue reference.

The rationale is that, when an object is potentially passed as a parameter by rvalue reference (which is what you are allowing by using std::forward), it's information content may be destroyed. So, you only want to do it when you are sure you no longer have any use for that information content.

Example:

#include <utility>

template <class T> void f(T &&t);
template <class T> void g(const T &t);

template <class T>
void outer(bool f_first, T &&t)
  {
    if (f_first)
      {
        f(t);
        g(t);
      }
    else
      {
        g(t);
        f(std::forward<T>(t));
      }
  }

#include <string>

void foo(std::string s)
  {
    outer(true, s);
    outer(true, s + "x");
    outer(false, s);
    outer(false, std::move(s));
  }
WaltK
  • 724
  • 4
  • 13