How to Fix C++ Perfect Forwarding and std::forward Errors
In this tutorial, you'll learn about How to Fix C++ Perfect Forwarding and std::forward Errors. We cover key concepts, practical examples, and best practices.
C++ perfect forwarding errors occur when std::forward is used incorrectly, forwarding references (T&&) are not properly deduced, or reference collapsing does not produce the expected type.
Quick Fix
Wrong
template <typename T>
void wrapper(T&& arg) {
// Wrong: arg is an lvalue here, always copies
process(arg);
}
void process(int&) { std::cout << "lvalue\n"; }
void process(int&&) { std::cout << "rvalue\n"; }
int main() {
int x = 42;
wrapper(x); // lvalue
wrapper(42); // rvalue? No, both print "lvalue"
}
lvalue
lvalue
Without std::forward, arg is always an lvalue inside the function.
Right
template <typename T>
void wrapper(T&& arg) {
process(std::forward<T>(arg));
}
void process(int&) { std::cout << "lvalue\n"; }
void process(int&&) { std::cout << "rvalue\n"; }
int main() {
int x = 42;
wrapper(x); // lvalue
wrapper(42); // rvalue
}
lvalue
rvalue
Fix for variadic templates
template <typename... Args>
auto make_vector(Args&&... args) {
return std::vector<int>{std::forward<Args>(args)...};
}
Fix for class templates (C++20)
struct Factory {
template <typename T, typename... Args>
static T create(Args&&... args) {
return T(std::forward<Args>(args)...);
}
};
Prevention
- Always use
std::forward<T>(arg)with forwarding references (T&&). - Never use
std::forwardwithout a template parameter. - Use
decltype(auto)for perfect forwarding return types. - Use forwarding references in variadic template arguments.
- Understand reference collapsing:
T& &collapses toT&,T& &&toT&,T&& &toT&,T&& &&toT&&.
DodaTech Tools
Doda Browser's C++ template instantiation viewer shows how reference collapsing and forwarding work for each call site. DodaZIP archives template specialization data. Durga Antivirus Pro detects unsafe forwarding that could expose references to temporaries.
Common Mistakes with perfect forwarding
- Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
- Non-exhaustive pattern matches that compile with warnings then crash at runtime
- Misunderstanding that
Stringis[Char]with poor performance for large text operations
These mistakes appear frequently in real-world CPP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro