What is Perfect Forwarding in C++: Explanation and Example
std::forward with universal references to achieve this, enabling efficient and correct argument passing.How It Works
Perfect forwarding works by capturing the exact type and value category (whether an argument is an lvalue or rvalue) of a function's parameters and then passing them on to another function without changing them. Imagine you are handing a package to a friend exactly as you received it, without opening or changing it. This way, the receiving function gets the argument in the same form it was originally given.
In C++, this is done using a special kind of reference called a universal (or forwarding) reference, which can bind to both lvalues and rvalues. The std::forward function then forwards the argument with its original type and value category intact. This avoids unnecessary copying or moving and ensures the called function behaves correctly depending on how the argument was passed.
Example
This example shows a template function that perfectly forwards its argument to another function, preserving whether the argument is an lvalue or rvalue.
#include <iostream> #include <utility> void process(int& x) { std::cout << "Lvalue processed: " << x << "\n"; } void process(int&& x) { std::cout << "Rvalue processed: " << x << "\n"; } template <typename T> void forwardToProcess(T&& arg) { process(std::forward<T>(arg)); } int main() { int a = 10; forwardToProcess(a); // Pass lvalue forwardToProcess(20); // Pass rvalue return 0; }
When to Use
Use perfect forwarding when writing template functions that forward arguments to other functions, especially in generic code like wrappers, factories, or forwarding constructors. It helps keep your code efficient by avoiding unnecessary copies and ensures the correct function overloads are called based on the argument type.
For example, in a factory function that creates objects, perfect forwarding lets you pass constructor arguments exactly as received, whether they are temporary objects or named variables. This makes your code flexible and fast.
Key Points
- Perfect forwarding preserves the original argument type and value category.
- It uses universal references and
std::forwardto achieve this. - It avoids unnecessary copies and moves, improving performance.
- Commonly used in template functions that forward arguments to other functions.