I saw the usage of something like
#include
#include
using namespace std;
template
void Foo(FN&&a
The rules for deduction of T&&
are tricky.
They where designed to make a deduced T&&
a "forwarding reference" (or "universal reference").
First, reference collapsing. Suppose you have an unknown type X. For now X
is not deduced.
Then if we examine variables of the following type:
typedef X x0;
typedef X& x1;
typedef X const& x2;
typedef X&& x3;
and we set X
to be one of int
, int&
, int const&
and int&&
, we get:
X is ---> int int& int const& int&&
X int int& int const& int&&
X& int& int& int const& int&
X const& int const& int& int const& int&
X&& int&& int& int const& int&&
live example.
The next bit comes with the deduction rules. If you pass X&
to T&&
in a deduced context, T
is deduced to be X&
. This causes T&&
to become X&
by the above reference collapsing rules. Similar things happen for X const&
.
If you pass X&&
to T&&
, it deduces T
to be X
. T&&
becomes X&&
as well.
Between the two of them, in a deduced context, template<class T> void foo(T&&t)
is a universal reference (well, now called a forwarding reference).
You can recover the r/l value category of t
with std::forward<T>(t)
, hence the name forwarding reference.
This allows one template to process both l and r values, and use std::forward
and similar machinery to behave slightly differently, if you want.
Only processing rvalues requires extra work: you have to use SFINAE or another overload (possibly with =delete
). Only processing lvalues is easy (just deduce with T&
).