C++ Reference Collapsing
Introduction
Because C++ template and type deduction, it is possible to have reference to reference in templates or typedefs. However, the resulting type of reference to reference could be confusing.
In this blog post, I would like to discuss the reference collapsing rules in C++.
Reference Collapsing
Reference Collapsing Rules
It is permitted to form references to references through type manipulations in templates or typedefs. rvalue reference to rvalue reference collapses to rvalue reference, all other combinations form lvalue reference.
T&& &&
→T&&
T& &&
→T&
T& &
→T&
T&& &
→T&
Universal Reference
Scott Meyers proposed the concept of “universal reference” to facilitate the user to understand T&&
in C++ and distinguish T&&
from conventional rvalue reference.
For example, the following is a declaration with universal reference.
1 | template<typename T> |
Universal reference states that if param
is a rvalue reference, T&&
will just serve as T&&
, otherwise, T&&
will just serve as T&
. However, technically universal reference is just rvalue reference to rvalue/lvalue reference and applying reference collapsing.
The only caveat for the above example is that
1 | int param{0}; |
auto
1 | std::vector<int> vec_0{0, 1, 2}; |
Type Alias
1 | typedef int& lref; |
In the scenario where type aliasing using typedef
is replaced with type aliasing using using
, the reference collapsing rule still applies.
1 | using lref = int&; |
decltype
decltype(expr)
yields T
, T&
, and T&&
, depending on expr
. The rules is specified at the decltype
CPP reference webpage.
If the argument is an unparenthesized id-expression or an unparenthesized class member access expression, then decltype yields the type of the entity named by this expression.
If the argument is any other expression of type T
, and
- if the value category of expression is xvalue, then decltype yields
T&&
; - if the value category of expression is lvalue, then decltype yields
T&
; - if the value category of expression is prvalue, then decltype yields
T
.
While xvalue, prvalue, and rvalue have been confusing to the user, some examples might just be straightforward to understand.
1 | std::vector<int> vec_0{0, 1, 2}; |
Notice that (vec_0)
is a lvalue expression (parenthesized expression if the unparenthesized expression is an lvalue) whereas vec_0
is a rvalue expression.
The reference collapsing rules also applies for types deduced by decltype
.
1 | std::vector<int> vec_0{0, 1, 2}; |
References
C++ Reference Collapsing