6

in scott meyers book he mentioned an implementation for std forward that goes like this (non std conformant)

template <typename T>
T&& forward(typename remove_reference<T>::type& param)
{
   return static_cast<T&&>(param);
}

The question is why do we need to remove reference here?

so a typical forward usage would be in a universal reference function as follows:

template <typename T>
void f(T&& fparam)
{
    g(forward<T>(fparam));  // assume there is g function.
}

without remove reference, the forward would look like this

template <typename T>
T&& forward(T& param);

now the two cases are:

  1. fparam is rvalue in that case inside f function the T is deduced as non reference object type so the forward call take the param by lvalue reference and cast it to T&& (because T is non reference).

  2. fparam is lvalue then inside f the T is deduced as T& then forward will take (as argument) a reference to an lvalue reference (collapsing to lvalue reference) then the static cast would be T& && which is again lvalue reference.

so why do we need to remove reference from param of forward? does it have to do with disallowing deducing types maybe? can somebody maybe give a detailed explanation.

The question that is referenced as duplicate is not, the answer basically says that the std library uses remove reference but why?

mkmostafa
  • 3,071
  • 2
  • 18
  • 47
  • Possible duplicate of [The implementation of std::forward](http://stackoverflow.com/questions/27501400/the-implementation-of-stdforward) – Vittorio Romeo Mar 22 '17 at 09:41

1 Answers1

7

Does it have to do with disallowing deducing types maybe?

Yes, typename std::remove_reference<T>::type introduces a non-deduced context. It prevents the user from mistakenly writing...

std::forward(something)

...and forces him/her to provide an explicit template argument:

std::forward<T>(something)
Community
  • 1
  • 1
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • thanks I guessed so but I wanted to be sure, I suppose maybe another std function with an explicit name that enforces non deduction would have been clearer. But is this the only reason to remove reference in the forward function? – mkmostafa Mar 22 '17 at 09:45
  • also meyers should have mentioned this :) – mkmostafa Mar 22 '17 at 09:48
  • Why _mistakenly_? What would be wrong/dangerous in using `forward` without specifying the template type? Why is this wrong/dangerous when using `move`? – Enlico Aug 03 '19 at 11:26
  • @EnricoMariaDeAngelis: `forward` is a conditional move, and the condition depends on the parameter you pass. Without a parameter, it is useless. `move` is an unconditional move, so it doesn't need any extra input. – Vittorio Romeo Aug 03 '19 at 11:50
  • [This anwer](https://stackoverflow.com/a/7780006/5825294) insists on the point that `forward` would be useless if it didn't take the explicit parameter. Anyway I haven't grasped it entirely. – Enlico Aug 03 '19 at 16:36
  • So `forward`'s intended use is that it is called by another template function, e.g. `callerFun`, whose template argument is of type `T`, so that type deduction takes place for `callerFun` when an object of class, say, `A` is passed to it, not for `forward`; `forward`, on the contrary, does not use template type deduction, since it receives the template argument explicitly, which can be either `A` (if an rvalue was passed to `callerFun`) or `A&` (if an lvalue was passed to `callerFun`); – Enlico Aug 03 '19 at 17:10
  • once `T` is either `A` or `A&`, the one or the other instantiation of `forward` is chosen, where the return type `T&&` resolves to either `A&&` or `A&` (through reference collapsing, not type deduction). – Enlico Aug 03 '19 at 17:11
  • @VittorioRomeo, can you please confirm/deny my understanding? – Enlico Aug 03 '19 at 17:12