When not to use std :: forward with r-values?

When is std::forward not required? It is used to wrap an argument to an internal function, which is templated-rvalue (that is, it can be lvalue or named-rvalue). How in:

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

I assume that one case is when the parameters of an internal function are passed by value. Are there any other cases? I have this question when I wrote std::begin(std::forward<Ct>(ct)) , where Ct is templated-rvalue-ref.

EDIT about possible duplication

If I remember correctly, this is the 3rd attempt to close this 4yr old question as a duplicate of a beginner who does not understand the question.

"The Benefits of Using Forwarding?" and "When not to use std :: forward with r-values?" these are very different questions. Firstly, an introduction to r-values ​​for beginners, and secondly, a discussion of ideal forwarding for an advanced C ++ user. I am the author of a meta-template library and a lambda library that do not require a detailed description of the basics. The information in the answer is very different from another question.

+7
source share
3 answers

I answer my question, because I have not yet received a satisfactory answer. If I get even a slight improvement / addition to this, I will choose your answer, as usual.

In general, std::forward will be useful with an internal function if the effect of perfect forwarding is achieved. Otherwise, it is superfluous.

Use std::forward to wrap the internal arg argument only if one of the following values ​​is true:

  • parameter of the internal function templated-rvalue-ref (now called a "forwarding link"); Internal function
  • has several overloads that differ based on the r / l-valueness parameter; Internal function
  • has several overloads that distinguish the constant-based lvalue parameter;
+2
source

Perfect forwarding is possible when the template parameter type contains a category of values. (If this sentence does not make sense, take a moment to familiarize yourself with this problem .)

Given:

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

In the body foo , T will either take the form U or U& . The first means that we were given an rvalue, the latter means that we passed an lvalue. We can forward this fact as follows:

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

Pass the lvalue value to foo , bar gets the same lvalue value. Pass the value of r foo , bar gets the value of r.

If you cannot distinguish between a category of values, a transfer is not necessary. This is only useful when you have a template parameter that is displayed in the same way as described above. So yes, here it is useless:

 template <typename T> void foo(const T& x) { // if this was called as foo(1), we're none the wiser } 
+6
source

Use std :: forward (in a formal parameter for a template function whose type is T & &, T is a template type parameter):

  • When the call to the internal function is the last use of the parameter in the external function and
  • When possible overloads of an internal function may or may not take a parameter as an rvalue reference.

The rationale is that when an object is potentially passed as a parameter using an rvalue reference (which you allow with std :: forward), the information content may be destroyed. Thus, you want to do this only if you are sure that you are no longer using this 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)); } 
-one
source

All Articles