Appearance
Perfect Forwarding
Perfect forwarding allows you to pass arguments through a function while preserving their original value category (l-value/r-value). This is essential for writing generic, efficient template code.
The Problem: Value Category Loss
cpp
void process(int& value);
void process(int&& value);
template<typename T>
void wrapper(T param) {
process(param); // Calls the l-value overload!
}
wrapper(42); // 42 is rvalue, but wrapper will call the l-value overload!The Solution: Universal References
cpp
template<typename T>
void wrapper(T&& param) { // Universal reference
process(std::forward<T>(param)); // Preserves value category
}
wrapper(42); // Calls process with rvalue
int x = 42;
wrapper(x); // Calls process with lvalueUniversal references are formed when:
T&&is used in a template parameter- Type deduction occurs
cpp
template<typename T>
void f(T&& param); // Universal reference
template<typename T>
class Widget {
void f(T&& param); // NOT universal reference (no deduction)
};std::forward
std::forward is used to forward the original value category of the argument to the function. How it works:
- If
Tis lvalue reference →static_cast<T&>(no change) - If
Tis not reference →static_cast<T&&>(to rvalue)
Questions
Q: What is the main purpose of perfect forwarding?
Perfect forwarding preserves the original value category (l-value/r-value) of arguments when passing them through template functions. This allows the called function to receive arguments with the same value category as they were originally passed.
Q: What is a universal reference?
A universal reference is formed when T&& is used in a template parameter and type deduction occurs. It can bind to both l-values and r-values, making it 'universal'.
Q: What does std::forward do?
std::forward conditionally casts to r-value reference only if the original argument was an r-value. If the original was an l-value, it remains an l-value.
Q: What happens when you pass an r-value to a template function with T&& parameter?
When passing an r-value to T&&, T is deduced as the type (not a reference), and param becomes an r-value reference to that type.
Q: What happens when you pass an l-value to a template function with T&& parameter?
When passing an l-value to T&&, T is deduced as l-value reference, and due to reference collapse, param becomes an l-value reference.
Q: Why is perfect forwarding important for generic code?
A: It reduces compilation time
Perfect forwarding allows generic functions to pass arguments to other functions while preserving their original value category, enabling proper overload resolution and efficient move semantics.
Q: What is the relationship between perfect forwarding and move semantics?
Perfect forwarding enables efficient move semantics in generic code by preserving r-value references, allowing move constructors and move assignment operators to be called when appropriate.