Fundamentals 5 min read

Understanding && in C++: Rvalue References, Forwarding References, and Their Use as Function Parameters

The article explains the different meanings of the && operator in C++—as a true rvalue reference in non‑template functions, as a forwarding (universal) reference in templates, and its behavior when binding to function return values—illustrated with code examples and practical guidelines.

IT Services Circle
IT Services Circle
IT Services Circle
Understanding && in C++: Rvalue References, Forwarding References, and Their Use as Function Parameters

C++11 introduced many new language features, among which the && operator often confuses beginners because it does not always denote an rvalue reference.

Scott Meyers famously noted that "T&& doesn't always mean 'rvalue reference'".

&& as a Function Parameter

In non‑template functions, && always represents an rvalue reference, so the function can only accept rvalue arguments.

class A {
...
};
void foo(A&& a) {
...
}

The foo function can be called with rvalues such as:

foo(A{});
A a;
foo(std::move(a));
A get_a() {
A a;
...
return a;
}
foo(get_a());

Calling it with an lvalue reference fails to compile:

A a1;
A& ar = a1;
foo(ar); // ERROR

In template functions, however, && does not necessarily mean an rvalue reference. When used as T&& in a deduced context, it is a forwarding reference (also called a universal reference), which can bind to both lvalues and rvalues.

template
void bar(T&& t) {
    ...
}

Consequently, bar can accept a wide variety of arguments:

bar(A{});
    A a;
    bar(std::move(a));
    bar(get_a());

    A a1;
    A& ar1 = a1;
    bar(ar1);

    const A& ar2 = a1;
    bar(ar2);

Not all && in templates are forwarding references. For example, a parameter of type vector && can only bind to rvalues:

template
void bar(vector
&& tv) {
    ...
}

Similarly, adding const to a deduced && makes it a true rvalue reference:

template
void bar(const T&& v) {
    ...
}

&& When Receiving Return Values

The confusion also appears when binding the result of a function call. Declaring a variable as A&& a = test1(); makes a an rvalue reference, while using auto&& a = test2(); creates a forwarding reference that can bind to any value category.

class A {
...
};
A&& a = test1(); // rvalue reference
auto&& a = test2(); // forwarding (universal) reference

If the type is explicitly specified (e.g., A&& ), it remains an rvalue reference and can only accept rvalues.

Understanding these distinctions helps avoid compilation errors and makes advanced C++ idioms like perfect forwarding clearer.

C++templatemove semanticsfunction parametersforwarding referencervalue reference
IT Services Circle
Written by

IT Services Circle

Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.