Question

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.

Was it helpful?

Solution 2

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;

OTHER TIPS

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
}

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));
  }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top