8

According to this link, template argument deduction is disallowed for std::forward, and std::remove_reference is helping us to achieve that. But how does using remove_reference prevent template deduction from happening here?

template <class S>
S&& forward(typename std::remove_reference<S>::type& t) noexcept
{
    return static_cast<S&&>(t);
}
Enlico
  • 23,259
  • 6
  • 48
  • 102
PapaDiHatti
  • 1,841
  • 19
  • 26

1 Answers1

10

S in the expression typename std::remove_reference<S>::type is a non-deduced context (specifically because S appears in the nested-name-specifier of a type specified using a qualified-id). Non-deduced contexts are, as the name suggests, contexts in which the template argument cannot be deduced.

This case provides an easy example to understand why. Say I had:

int i;
forward(i);

What would S be? It could be int, int&, or int&& - all of those types would yield the correct argument type for the function. It's simply impossible for the compiler to determine which S you really mean here - so it doesn't try. It's non-deducible, so you have to explicitly provide which S you mean:

forward<int&>(i); // oh, got it, you meant S=int&
Barry
  • 286,269
  • 29
  • 621
  • 977
  • 1
    "I could have an entirely unrelated type `Foo` for which I specialize `remove_reference` to have the type `int`." That's technically UB :) – T.C. May 24 '16 at 16:00
  • @T.C., why would that be UB? Isn't it "only" terrible design, just like implementing `operator+` to make a subtraction-like operation? Or maybe it is UB because we are specializing a `std::` function? Ok, just that: [_The behavior of a program that adds specializations for `remove_reference` is undefined._](https://en.cppreference.com/w/cpp/types/remove_reference) – Enlico Nov 22 '20 at 15:33