How to Use std::forward in C++: Simple Guide and Examples
Use
std::forward in C++ to pass function arguments while preserving their original value category (lvalue or rvalue). It is mainly used in template functions to enable perfect forwarding, ensuring efficient and correct argument passing.Syntax
The syntax of std::forward is:
template<typename T>
T&& std::forward(std::remove_reference_t<T>& param) noexcept;Here:
Tis the template type parameter representing the argument type.paramis the function parameter passed as an lvalue reference to a type with references removed.std::forward<T>(param)castsparamback to its original value category (lvalue or rvalue).
This allows forwarding the argument exactly as it was received.
cpp
template<typename T> T&& forward(std::remove_reference_t<T>& param) noexcept; // Usage inside a template function: // std::forward<T>(param) forwards param preserving lvalue/rvalue nature
Example
This example shows how std::forward preserves the value category of arguments when forwarding them through a template function.
cpp
#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 relay(T&& arg) { process(std::forward<T>(arg)); } int main() { int a = 10; relay(a); // passes lvalue relay(20); // passes rvalue return 0; }
Output
Lvalue processed: 10
Rvalue processed: 20
Common Pitfalls
Common mistakes when using std::forward include:
- Using
std::forwardwith a non-template type, which can cause incorrect casts. - Forgetting to use the template parameter
Tinsidestd::forward<T>, which breaks perfect forwarding. - Using
std::moveinstead ofstd::forwardin forwarding functions, which always casts to rvalue and can cause unnecessary moves.
cpp
#include <iostream> #include <utility> void process(int& x) { std::cout << "Lvalue processed: " << x << '\n'; } void process(int&& x) { std::cout << "Rvalue processed: " << x << '\n'; } // Wrong: std::forward used without template parameter // template<typename T> // void relay_wrong(T&& arg) { // process(std::forward(arg)); // Error: missing <T> // } // Wrong: using std::move instead of std::forward template<typename T> void relay_move(T&& arg) { process(std::move(arg)); // Always treats arg as rvalue } int main() { int a = 10; relay_move(a); // Calls rvalue version incorrectly return 0; }
Output
Rvalue processed: 10
Quick Reference
Tips for using std::forward:
- Use
std::forward<T>(arg)inside template functions with universal references (T&&). - It preserves whether the argument is an lvalue or rvalue.
- Do not use
std::forwardwith non-template or fixed types. - Use
std::moveonly when you want to unconditionally cast to rvalue.
Key Takeaways
Use std::forward in template functions to perfectly forward arguments preserving lvalue/rvalue nature.
Always specify the template parameter T in std::forward(arg) to avoid incorrect casts.
Do not use std::forward with non-template types; it is designed for universal references.
Use std::move only when you want to force an rvalue cast, not for perfect forwarding.
Perfect forwarding improves efficiency by avoiding unnecessary copies or moves.