forwarding reference

C++98 didn’t have rvalue references, only “references” — what we now call “lvalue references.” The rule was simply that a mutable reference would bind only to a mutable lvalue, but a const reference could bind to anything.
```
void change(int&);
void observe(const int&);

int main() {
    int i = 41;
    change(i);    // OK, lvalue
    change(42);   // Error, rvalue
    observe(i);   // OK, lvalue
    observe(42);  // OK, rvalue
}
```
This applies even when that type int comes from type deduction:
```
template<class T>
void observe(const T&);

int main() {
    int i = 41;
    const int ci = 42;
    observe(i);   // OK, lvalue, T=int
    observe(ci);  // OK, lvalue, T=int
    observe(43);  // OK, rvalue, T=int
}
```
When C++11 invented rvalue references, none of this behavior changed at all. const T& still binds happily to both lvalues and rvalues.
const T& is the O.G. forwarding reference.
C++11 also invented the forwarding reference: that when there’s a deduced type T directly modified by &&, T can sometimes be deduced as an lvalue reference type (even though this never happens anywhere else in the language).
```
template<class T>
void forward(T&&);

int main() {
    int i = 41;
    const int ci = 42;
    forward(i);   // OK, lvalue, T=int&
    forward(ci);  // OK, lvalue, T=const int&
    forward(43);  // OK, rvalue, T=int
}
```
The advantage of T&& is that, by looking at whether T deduced as a reference type, you can tell whether your caller considered the argument an lvalue or an rvalue. That’s not useful information in its own right; it is useful only if you are planning to forward your argument as its original value category — lvalues as lvalues, rvalues as rvalues. That’s what std::forward<T>(t) is for.
If you see code using std::forward<T> without an originating T&&, it’s almost certainly buggy. If you see code using (deduced) T&& without std::forward<T>, it’s either buggy or it’s C++20 Ranges. (Ranges ill-advisedly uses value category to denote lifetime rather than preferability, so Ranges code tends to forward rvalueness much more conservatively than ordinary C++ code does.)
In exchange for this advantage — forwardability — you pay in template bloat. Notice that we get three different instantiations of void forward(T&&) above, whereas we got only a single template instantiation of void observe(const T&).
Forwarding references should generally be used only where there’s an actual need for them; they shouldn’t be the first tool you reach for.