C++11 brought in new reference type – rvalue reference. This reference is declared using “
&&”. There are a whole slew of articles on how to distinguish between rvlaue and lvalue references, but we won’t go into this here. There are several very good articles listed in the references section.
One would assume that any declaration that uses “
&&” will always represent rvalue reference. However, it is not necessarily the case – sometimes it means rvalue reference, but sometimes it means either rvalue reference or lvalue reference. Scott Myers calls “
&&” universal reference.
If a variable or parameter is declared to have type
T&& for some deduced type
T, that variable or parameter is a universal reference.
Let’s conciser some examples:
template<typename T> void f(std::vector<T>&& param);
In this case the type is explicitly specified –
std:vector<T>. It doesn’t matter that the vector is templated, the vector itself is fixed. As a result, the
param is rvalue reference.
template<typename T> void f(T&& param);
param is universal reference. If the template
T is of an lvalue reference type, then based on the reference collapsing rules the final type becomes lvalue reference. If it is of rvalue reference – final type stays rvalue reference.
Keep in mind that regardless of the reference state the
param is lvalue reference inside the
f function. Simply because “if you can take its address it is lvalue reference”. The reference can be changed, or moved, to rvalue reference using