I just made some research about those (quite) new features and I wonder why C++ Committee decided to introduce the same syntax for both of them? It seems that developers unnecessary have to waste some time to understand how it works, and one solution lets to think about further problems. In my case it started from problem which can be simplified to this:
#include <iostream>
template <typename T>
void f(T& a)
{
std::cout << "f(T& a) for lvalues\n";
}
template <typename T>
void f(T&& a)
{
std::cout << "f(T&& a) for rvalues\n";
}
int main()
{
int a;
f(a);
f(int());
return 0;
}
I compiled it firstly on VS2013 and it worked as I expected, with this results:
f(T& a) for lvalues
f(T&& a) for rvalues
But there was one suspicious thing: intellisense underlined f(a). I made some research and I understood that it is because type collapsing (universal references as Scott Meyers named it), so I wondered what g++ thinks about it. Of course it didn't compiled. It is very nice that Microsoft implemented their compiler to work in more intuitive way, but I'm not sure if it is according to the standard and if there should be this kind of difference in IDE (compiler vs intellisense, but in fact there may be some sense in it). Ok, return to the problem. I solved it in this way:
template <typename T>
void f(T& a)
{
std::cout << "f(T& a) for lvalues\n";
}
template <typename T>
void f(const T&& a)
{
std::cout << "f(T&& a) for rvalues\n";
}
Now there wasn't any type collapsing, just normal overloading for (r/l)values. It compiled on g++, intellisense stopped complaining and I was almost satisfied. Almost, because I thought about what if I will want to change something in object's state which is passed by rvalue reference? I could describe some situation when it could be necessary, but this description is too long to present it here. I solved it in this way:
template <typename T>
void f(T&& a, std::true_type)
{
std::cout << "f(T&& a) for rvalues\n";
}
template <typename T>
void f(T&& a, std::false_type)
{
std::cout << "f(T&& a) for lvalues\n";
}
template <typename T>
void f(T&& a)
{
f(std::forward<T>(a), std::is_rvalue_reference<T&&>());
}
Now it compiles on all tested compilers and it lets me to change object state in rvalue reference implementation, but it doesn't looks very nice, and this is because of the same syntax for universal references and rvalue references. So my question is: Why C++ Committee didn't introduce some another syntax for universal references? I think that this feature should be signalized, for example, by T?, auto?, or something similar, but not as T&& and auto&& which just collide with rvalue references. Using this approach my first implementation would be perfectly correct, not only for MS compiler. Can anyone explain Committee decision?
You answered your own question: "universal reference" is just a name for the rvalue reference case of reference collapsing. If another syntax were required for reference collapsing, it wouldn't be reference collapsing any more. Reference collapsing is simply applying a reference qualifier to a reference type.
Your first example is well-formed. GCC 4.9 compiles it without complaint, and the output agrees with MSVC.
Rvalue references do not apply
const
semantics; you can always change the state of an object passed bymove
. Mutability is necessary to their purpose. Although there is such a thing asconst &&
, you should never need it.