0

I have found in std library the following implementation of std::forward:

// TEMPLATE FUNCTION forward
template<class _Ty> inline
constexpr _Ty&& forward(
    typename remove_reference<_Ty>::type& _Arg) _NOEXCEPT
{   // forward an lvalue as either an lvalue or an rvalue
return (static_cast<_Ty&&>(_Arg));
}

template<class _Ty> inline
constexpr _Ty&& forward(
    typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{   // forward an rvalue as an rvalue
static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}

First function works obviously, but for second I cannot find usefull example. If I try to do something like this:

template<class _Ty> inline
constexpr _Ty&& my_forward(
   typename std::remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{   // forward an rvalue as an rvalue
   static_assert(!std::is_lvalue_reference<_Ty>::value, "bad forward call");
   return (static_cast<_Ty&&>(_Arg));
}

template<typename T>
T getRValue()
{
    return std::remove_reference<T>::type{};
}

template<typename T>
void setValue(T && i)
{
   my_forward<T>(getRValue<T>());
}

int main()
{
    int i = 1;
    setValue(i);
}

to check when second function is called, I have got the error:

Error   C2664   '_Ty my_forward<T>(int &&) noexcept': cannot convert argument 1 from 'int' to 'int &&'

Does anybody know in which case second overloaded function (in my terms my_forward) is called ? Or may be some good example for it ? By the way my compiler is MSVC 2015

Thanks, all for help !!

Denis Kotov
  • 857
  • 2
  • 10
  • 29
  • The comment says "forward an rvalue as an rvalue" but you forward an rvalue lvalue as an lvalue (and have a case of undefined behavior aswell). That's not what the function is written for. – Johannes Schaub - litb Feb 26 '17 at 11:32
  • @Johannes Schaub: Why ? getRValue() provide prvalue and it can be put as parameter to my_forward. Could you give a usefull example of using my_forward for rvalue as in my example ? – Denis Kotov Feb 26 '17 at 11:50
  • @DenisKotov: "*getRValue() provide prvalue*" Does it? It returns a `T`, but `T` can be a reference. And thus, it could be an lvalue. – Nicol Bolas Feb 26 '17 at 15:32
  • @Johannes Schaub: Sorry for incorrect. It is _xvalue_, but not _lvalue_, because return value of function can be reused, but it does not have a name yet – Denis Kotov Feb 26 '17 at 19:50
  • This is also very relevant - http://stackoverflow.com/q/29135698/241631 – Praetorian Feb 28 '17 at 20:18
  • @Praetorian: I have been interested in which cases called second overloaded and have figured out it – Denis Kotov Feb 28 '17 at 20:26

2 Answers2

0
int bad_forward_call() {
  return std::forward<int&>(7);
}

this will invoke that version.

Note I'm forwarding an rvalue as an lvalue. Not allowed.

Your getRValue fails to get an rvalue if T is a reference type.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
0

I have found cases in which this function is called:

my_forward<int&>(8); // This calls forward(typename remove_reference<_Ty>::type&& _Arg)
But it won't compile 'cause we try convert rvalue to lvalue

my_forward<int&&>(8); // This calls forward(typename remove_reference<_Ty>::type&& _Arg)
But it compiles successfully

If it may be useful for somebody, the purpose of std::forward is to forward operation to another class or function.

Consider the following example:

template<typename T>
void precompute(T & t)
{
   std::cout << "lvalue reference";
}

template<typename T, 
         std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
   std::cout << "rvalue reference";
}

template<typename T>
void calculate(T && t)
{
   precompute(t); // Every time called precompute(T & t)
}

or like this:

template<typename T>
void precompute(T & t)
{
   std::cout << "lvalue reference";
}

template<typename T, 
         std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
   std::cout << "rvalue reference";
}

template<typename T>
void calculate(T && t)
{
   precompute(std::move(t)); // Every time called precompute(T && t)
}

As you can see we have a problem !! Neither of two examples satisfied us.

In first example every time will be called lvalue function and nothing can be done to call first with rvalue.

In second example every time will be called rvalue function and nothing can be done to call first with lvalue.

The solution is to forward making decision to the called function:

template<typename T>
void precompute(T & t)
{
   std::cout << "lvalue reference";
}

template<typename T, 
         std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
   std::cout << "rvalue reference";
}

template<typename T>
void calculate(T && t)
{
   precompute(std::forward<T>(t)); // Will be called either precompute(T & t) or precompute(T && t) depends on type of t
}

In this case we have to be sure that will be called appropriate version. That is why we forward (means: "Please, check type of t and if it is rvalue -> call rvalue version of function, and if it is lvalue -> call lvalue version of function") this operation to called function.

Denis Kotov
  • 857
  • 2
  • 10
  • 29