Hacker News new | ask | show | jobs
by splinterofchaos 4234 days ago
Not a bad article, but I'm so sick of the term "universal references". Perhaps useful for explaining things to the uninitiate, but a more technical understanding requires the knowledge that rvalue references can be made from any l- or rvalue.

So when I see "Don't let T&& fool you here - T is not an rvalue reference" -- yes it fricking is! And if you're going to work on a low enough type-level that you need perfect forwarding, you NEED TO KNOW THAT.

4 comments

> So when I see "Don't let T&& fool you here - T is not an rvalue reference" -- yes it fricking is!

T&& is only an rvalue reference when T is a non-lvalue-reference type. If T = U& then T&& = U& because of the reference collapsing rules. If you're saying that you should understand how type deduction works and interacts with reference collapsing if you're going to write C++11 then I agree. Like much of C++, perfect forwarding's design is an ugly mess and is not amenable to a superficial understanding unless you like shooting yourself in the foot.

At C++Now 2014 there was some agreement on renaming 'universal references' to 'forwarding references'. Apparently, Scott Meyers, the guy that came up with the term universal references, even agreed to update his upcoming book with the new term.
At least "forwarding" specifies "for use in perfect forwarding", but it must be made clear that this term refers to the syntactic phenomena and they are not distinct from rvalue references.
| but a more technical understanding requires the knowledge that rvalue references can bind to any l- or rvalue

I don't think that's true. rvalue references can only bind to rvalues.

Here's a complete program. foo(i) won't compile bacause i is not an rvalue. bar(i) will compile, and foo(1) will compile.

#include <iostream>

using namespace std;

int foo(int&& i){ return i; }

template<class T> T bar(T&& i){ return i; }

int main() { int i=0; cout << foo(i) << endl;

   return 0;
}

edit: I am replying humbly. C++ is a complex language and I might very well be wrong.

I did not mean "any rvalue-reference" and bind to "any l- or rvalue", but that you can have an "int &&", "int& &&", "const int& &&", and even "int&& &&". I updated my comment to say "can be made from" instead "can bind to".

Your code example does not work because you call "foo" instead of "bar". But consider this one:

#include <iostream>

using namespace std;

template<class T> T bar(T&& i){ return std::forward<T>(i); }

int main() {

  int i=0;

  cout << bar<int&&>(6) << endl;

  return 0;

}
Maybe you're confusing reference collapsing with universal references?

In your example, replace bar<int&&>(6) to bar<int&&>(i).

It won't compile because i is not an r value. bar(i) will compile, because the template parameter is a universal reverence that will become an lvalue (not an rvalue) through reference collapsing.

I called "bar" with "<int&&>" to demonstrate that you can bind an rvalue-ref to an rvalue-ref, not to suggest that's how it should be called.
This is exactly what the linked article says about universal references, by the way. Did you actually read it, or just got angry at the title?