Saturday, October 6, 2012

New Article: "Universal References in C++11"

One of the most difficult aspects of C++11 for me to wrap my head around was the meaning of "T&&" in type declarations.  “It means rvalue reference,” I was told, and that was fine until I was also told that in some cases, it actually means lvalue reference.  I fought with this seeming contradiction for a couple of years before my head cleared and I decided that we need to distinguish declarations for rvalue references from declarations for things that look like rvalue references, but may not be.  I call these latter things universal references.  I hope the term catches on, because I think it makes the matter a lot easier to understand.

I gave a talk on universal references at this year's C++ and Beyond, and a video of that talk should go live sometime this month.  (I'll let you know when.)  I also wrote an article on the topic for ACCU's Overload, and the issue with the article (PDF) has just been published.  This is from the beginning of that article:
Given that rvalue references are declared using “&&”, it seems reasonable to assume that the presence of “&&” in a type declaration indicates an rvalue reference. That is not the case:
Widget&& var1 = someWidget;       // here, “&&” means rvalue reference

auto&& var2 = var1;               // here, “&&” does not mean rvalue reference

template<typename T>
void f(std::vector<T>&& param);   // here, “&&” means rvalue reference

template<typename T>
void f(T&& param);                // here, “&&” does not mean rvalue reference
In this article, I describe the two meanings of “&&” in type declarations, explain how to tell them apart, and introduce new terminology that makes it possible to unambiguously communicate which meaning of “&&” is intended. Distinguishing the different meanings is important, because if you think “rvalue reference” whenever you see “&&” in a type declaration, you’ll misread a lot of C++11 code.
I hope you find the article both interesting and useful.



Michal Mocny said...

Can't wait to read this, and looking forward to the video!

Gennadiy said...

I believe there is a small hole in the article

class Widget {
void foo( T&& arg );

Here arg can be both rvalue and lvalue ref. If T is R&, arg is R&, no?

Scott Meyers said...

@Gennadiy: Yes, given

template<typename T>
class Widget {
void foo( T&& arg );

the class Widget<type&> would contain the function

void Widget::foo(type& arg);

instead of

void Widget::foo(type&& arg);

Thanks for pointing this out.