3

I'm learning about templates and particularly std::forward; when I check its implementation it uses another class template std::remove_reference in its arguments list:

template<class _Ty>
_Ty&& forward(typename remove_reference<_Ty>::type& _Arg)
{// forward an lvalue as either an lvalue or an rvalue
   // ...
}

btw: I've removed a few things like inline, constexpr, NO_EXCEPT and the body of the function for clarity

I read about how types are deduced when the template parameter is a pointer(_Ty*), reference(_Ty&), universal reference(_Ty) and where its just the type itself (_Ty). In this case it is a reference but it has that added removed_reference<_Ty>::type preceding it; the _Ty and the reference are split by the call to remove_reference. How does the compiler figure out the type of _Ty?

The function template has to figure out the template parameters using the arguments passed in to the function(when not explicitly defining them in the function call) but in this case remove_reference is also a class template that needs to figure out the type of _Ty as well. It seems almost like a catch 22 for me because std::forward needs to figure out _Ty using its function argument but its function argument which is std::remove_reference<_Ty> needs to already know what _Ty is. All This tells me is that I have a flawed understanding of how templates work but I don't know where.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
masonCherry
  • 894
  • 6
  • 14

3 Answers3

4

how does the compiler figure out the type of _Ty?

It doesn't. std::forward is meant to be used with the type provided explicitly. And it's enforced by accepting the function argument to std::forward with the type typename remove_reference<_Ty>::type, where _Ty is in a non-deduced context. The compiler can't deduce it.

A typical use with a forwarding reference is as follows:

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

Strictly speaking, std::forward is just syntactic sugar for a cast to T&& above. It's reference collapsing the does all the magic, but a bare cast to T&& does not convey the intent to forward quite as clearly as a named operator. That is why std::forward exists.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • I completely did not look at this from a practical use case point of view I simply saw the function and tried to guess at how it worked. So your example with `foo` when `foo` gets an rvalue the type of `T` is `&&` and specifying that explicitly as `std::forward(t)` invokes the partial specialization of `std::remove_reference` that takes template parameter `T` as `T&&`. Also due to the reference collapsing that you mentioned `t` would be an rvalue and thus invoke the `std::forward` implementation that takes and rvalue. Is this all correct? Why do both `std::forward` implementations return && – masonCherry May 30 '19 at 17:58
  • 1
    @MrBrN197 - Both return `&&` because applying it to an lvalue reference will leave it an lvalue reference (due to reference collapsing). – StoryTeller - Unslander Monica May 30 '19 at 18:10
3

It does not deduce it. This is why when you use std::forward you have to give it template argument:

std::forward<T>(t);

This is contrary to std::move, which does deduce, and typically used like this:

std::move(t);
SergeyA
  • 61,605
  • 5
  • 78
  • 137
2

How does std::forward deduce the type of _Ty?

Ty doesn't have a type. Ty is a type (template parameter). The compiler doesn't deduce the type.

how does the compiler figure out the type of _Ty?

The template argument has to be passed explicitly.

If the type were deduced, then:

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

would pass an lvalue, since t is an lvalue. But we want to pass an rvalue, because t is an rvalue reference. Because the deduction is counter-productive, it is disabled using the remove_reference<_Ty>::type& trick, and we must write correctly:

template<class T>
void foo(T&& t) {
    bar(std::forward<T>(t));
                 // ^^^ this is how the compiler knows
}
eerorika
  • 232,697
  • 12
  • 197
  • 326