Skip to content

How to Fix C++ Perfect Forwarding and std::forward Errors

DodaTech Updated 2026-06-24 2 min read

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.

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::forward without a template parameter.
  • Use decltype(auto) for perfect forwarding return types.
  • Use forwarding references in variadic template arguments.
  • Understand reference collapsing: T& & collapses to T&, T& && to T&, T&& & to T&, T&& && to T&&.

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

  1. Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
  2. Non-exhaustive pattern matches that compile with warnings then crash at runtime
  3. Misunderstanding that String is [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

What is a forwarding reference in C++?

A forwarding reference (also called universal reference) is T&& where T is a deduced template parameter. It can bind to both lvalues (collapsing to T&) and rvalues (staying as T&&).

What is the difference between `std::move` and `std::forward`?

std::move unconditionally casts to an rvalue reference. std::forward conditionally casts to an rvalue reference only if the original argument was an rvalue. Use std::move when you know the value is expiring; use std::forward in template code.

Why does `std::forward` need the template type parameter?

std::forward<T>(arg) needs T to determine whether arg was originally an lvalue or rvalue. If T is int&, the reference collapsing makes the return type int&. If T is int, the return type is int&&.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro