What are Reference Collapsing Rules in C++?
Last Updated :
13 Aug, 2024
In C++, we have a very useful feature called reference collapsing, which comes into play when dealing with references to references, especially in the context of templates. It is very important to make templates work seamlessly with references, ensuring that code behaves consistently and as expected.
In this article, we will learn what reference collapsing is, why it is important, and how it works in C++.
What is Reference Collapsing in C++?
In C++, a reference is an alias for another variable. References themselves cannot be references, meaning we can't have a reference to a reference directly. However, in templates or other scenarios involving type deduction, we may encounter situations where a reference to a reference could theoretically exist. Reference collapsing rules dictate how these references are handled by the compiler to produce a valid type.
Need of Reference Collapsing
Reference collapsing is used for writing generic and flexible code using templates. Without reference collapsing, templates that involve references could lead to complex and unintuitive behavior or even compilation errors. Reference collapsing rules ensure that templates behave predictably, making it easier to write and maintain code.
Reference Collapsing Rules
The rules of reference collapsing in C++ can be summarized as follows:
- T& & becomes T&: If we try to form a reference to a reference where both are lvalue references (&), it collapses to a single lvalue reference.
- T& && becomes T&: If we have an lvalue reference to an rvalue reference, it collapses to an lvalue reference.
- T&& & becomes T&: If we have an rvalue reference to an lvalue reference, it collapses to an lvalue reference.
- T&& && becomes T&&: If we have an rvalue reference to an rvalue reference, it remains an rvalue reference.
These rules ensure that no matter how references are combined, the result is a valid reference type.
Example of Reference Collapsing
The below example will help to understand how reference collapsing rules are applied.
C++
// C++ program demonstrating reference collapsing rules
// using various template functions
#include <iostream>
#include <utility>
using namespace std;
// Function that demonstrates lvalue reference handling
template<typename T>
void func1(T& a) {
// Inform that func1 is called with lvalue reference (T&)
cout << "func1 called with lvalue reference (T&)" << endl;
// T& remains as T&
T& ref = a;
// Display the value of ref
cout << "Value of ref: " << ref << endl;
}
// Function that demonstrates rvalue reference handling and collapsing when passed an lvalue
template<typename T>
void func2(T&& a) {
// Inform that func2 is called with rvalue reference (T&&)
cout << "func2 called with rvalue reference (T&&)" << endl;
// T&& remains T&& or collapses to T& if T is lvalue reference
T&& ref = forward<T>(a);
// Display the value of ref
cout << "Value of ref: " << ref << endl;
}
int main() {
// Initialize an integer variable x with value 10
int x = 10;
// Call func1 with lvalue (x)
cout << "Calling func1 with lvalue (x):" << endl;
func1(x); // T deduced as int, ref becomes int&
// Call func2 with lvalue (x)
cout << "\nCalling func2 with lvalue (x):" << endl;
func2(x); // T deduced as int&, ref becomes int& due to reference collapsing
// Call func2 with rvalue (std::move(x))
cout << "\nCalling func2 with rvalue (move(x)):" << endl;
func2(move(x)); // T deduced as int, ref becomes int&&
return 0;
}
OutputCalling func1 with lvalue (x):
func1 called with lvalue reference (T&)
Value of ref: 10
Calling func2 with lvalue (x):
func2 called with rvalue reference (T&&)
Value of ref: 10
Calling func2 with rvalue (move(x)):
func2 called with rvalue reference (T&&)
Value of ref: 10
Conclusion
Reference collapsing is an advanced but essential concept in C++ that ensures templates and functions work correctly with different types of references. By understanding and applying the rules of reference collapsing, we can write more flexible and efficient code, particularly when working with templates and perfect forwarding. This feature of C++ helps maintain the consistency and predictability of reference types, making C++ a more powerful and versatile language for system and application development.
Similar Reads
Return by reference in C++ with Examples Pointers and References in C++ held close relation with one another. The major difference is that the pointers can be operated on like adding values whereas references are just an alias for another variable. Functions in C++ can return a reference as it's returns a pointer.When function returns a re
3 min read
is_rvalue_reference Template in C++ The std::is_rvalue_reference template of C++ STL is used to check whether the type is a rvalue reference type or not. It returns a boolean value showing the same. Syntax: template <class T > struct is_rvalue_reference; Parameters: This template accepts a single parameter T (Trait class) to che
2 min read
Passing Map as Reference in C++ STL Prerequisite: Maps in C++ STL Pass by reference Elements in the map are in form of pairs where the first is key and another value, denoting key-value pairs. Also, all the key values are unique means no two elements can have the same key value. Passing maps by value is a costly task, costly in terms
3 min read
is_reference Template in C++ The std::is_reference template of C++ STL is used to check whether the type is a reference type or not. It returns a boolean value showing the same. Syntax: template <class T > struct is_reference; Parameter: This template accepts a single parameter T (Trait class) to check whether T is a refe
2 min read
std::add_lvalue_reference in C++ with Examples The std::add_lvalue_reference template of C++ STL is present in the <type_traits> header file. The std::add_lvalue_reference template of C++ STL is used to get lvalue reference type that refers to T type. An lvalue reference is formed by placing an '&' after some type. An rvalue reference
2 min read
Pointers and References in C++ In C++ pointers and references both are mechanisms used to deal with memory, memory address, and data in a program. Pointers are used to store the memory address of another variable whereas references are used to create an alias for an already existing variable. Pointers in C++ Pointers in C++ are a
5 min read
lvalues references and rvalues references in C++ with Examples Prerequisites: lvalue and rvalue in C++, References in C++âl-valueâ refers to a memory location that identifies an object. "r-valueâ refers to the data value that is stored at some address in memory. References in C++ are nothing but the alternative to the already existing variable. They are declare
4 min read
When Do We Pass Arguments by Reference or Pointer in C++? In C++, we can pass arguments to a function as a value, reference (or pointer). Each method has its unique benefits and uses. In this article, we will discuss the application or cases where we should pass the arguments by reference or a pointer. But first, letâs quickly revisit the definitions of po
4 min read
Pointers vs References in C++ Prerequisite: Pointers, References C and C++ support pointers, which is different from most other programming languages such as Java, Python, Ruby, Perl and PHP as they only support references. But interestingly, C++, along with pointers, also supports references. On the surface, both references and
5 min read
reference_wrapper in C++ std::reference_wrapper is a class template that wraps a reference in a copy constructible and copy assignable object or reference to function of type T. Instances of std::reference_wrapper are objects (they can be copied or stored in containers) but they are implicitly convertible to âT&â so tha
1 min read