4 comments:

I definitively like and share your concept of universal reference. It really helps practically. After watching your talk, I went back on all my code make use of && and found a lots of subtle errors, not only thanks to the notion of universal reference, but also because you describe how the reference collapsing rules work in C++<=11 with precision. Thanks a lots Scott!

Firstly, thanks for such a nice article. I had to read a few sections of the standard more than once to correlate with the concepts.

In the section titled 'Nitty Gritty Details', I don't think I have understood the paragraph 'For example, given the type for both r1 and r2 is considered to be int in a call to the template f.'. Will appreciate if you could clarify this a bit more.

Also, in the very next paragraph, I have understood it in the following way. Is it correct?

r1 and r2 are both lvalue expresions. The function template under consideration are

For the case of r1, therefore, 14.8.2.1 / 3 applies "If P is an rvalue reference to a cvunqualified template parameter and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction."

Therefore T is int &, and the deduced A is int & &&, which is nothing but int & due to reference collapsing.

For the case of r2, 14.8.2.1/3 applies - "If P is a reference type, the type referred to by P is used for type deduction."

@Anubhav: When references such as r1 and r2 are passed as function arguments, the first thing that happens is that they're stripped of their referenceness. This is per 5/5: "If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis."

In the calls to f, both r1 and r2 are treated the same way. Their types are first converted to int (per 5/5 above). Then 14.8.2.1/3 kicks in for f. f's parameter type is "is an rvalue reference to a cv-unqualified template parameter and the argument is an lvalue," so both r1 and r2 lead to a deduced type of int& for the template parameter T. From there, it's just reference-collapsing. So both f(r1) and f(r2) invoke f<int&>(int&).