When talking about
T&& in C++, you may have heard about universal references and forwarding references. This may get you wonder. Why there are two names for an apparently same concept? Is there any difference between them? Which one should I use? Let’s find out.
Since C++11, two successive ampersands no longer mean just logical and but they are also used to denote so-called rvalue references. However, as many C++ programmers soon find out, not all occurrences of
type&& are the same. For example, consider the following code:
void foo(int&& i); template <typename T> void bar(T&& i);
When you try to call
foo(), it works as expected:
foo(1); // OK, 1 is an rvalue int k = 0; foo(k); // error: cannot bind 'int' lvalue to 'int&&'
bar(), there is a twist:
bar(1); // OK int k = 0; bar(k); // OK (?!)
The reason is that when you are in a template and a parameter has exactly type
T&& for some deduced type
T, then what you might get when instantiating the template is not an rvalue reference. Indeed, in the above case, the parameter of
bar() binds to both lvalues and rvalues. On a side note,
Since the C++11 standard (or even C++14 for that matter) does not distinguish between true rvalue references and what looks like an rvalue reference but might end up being an lvalue reference, Scott Meyers rightfully decided that we need a name for the latter. And so he coined the term universal references. For example, in the code above, the
int&& in the declaration of
foo() is an rvalue reference but the
T&& in the
bar() declaration is a universal reference. The sense behind the name is that a universal reference binds to both lvalues and rvalues, unlike lvalue references to non-const objects (they bind only to modifiable lvalues) and rvalue references (they bind only to rvalues). See Scott’s article for more details.
And so programmers started to use the term, as you can clearly see when you try to google it.
Later, several members of the C++ standard committee acknowledged the fact that we need a name for the
T&& references. However, they decided that a universal reference is not an ideal name, and came up with the term forwarding references in the form of a proposal for the C++1z standard.
I recommend you to read the proposal. It is short (basically three pages), well-written, and answers several questions, including Why not universal reference? Do we really need a name? and What about auto&&?
So, Is There Any Difference Between the Two Terms?
No. They are just different names for the same concept.
Which One Should I Use?
As of C++1z, the name forwarding reference should be part of the standard. For this reason, I recommend you to use it. However, bear in mind that the name universal reference has been with us for quite a while and is used in many articles.
What about you? Do you like the new name, or would you rather keep using the original one?