By trying to solve this problem, something made me wonder. Consider the following code:
template <typename T>
struct foo
{
foo(T const& x) : data(x) {}
T data;
};
It seems that I can construct an object of type foo<T const&>
without error, the hypothetical T const& const&
being understood as T const&
.
It seems also that this is called reference collapsing, but I never heard this term before (see comments in the linked question).
Is this widespread? Is this standard?
Reference collapsing is the mechanism that leads to universal references (which are really just rvalue references in situations where reference-collapsing takes place) sometimes resolving to lvalue references and sometimes to rvalue references.
When t is a forwarding reference (a function argument that is declared as an rvalue reference to a cv-unqualified function template parameter), this overload forwards the argument to another function with the value category it had when passed to the calling function.
A reference variable declaration is any simple declaration whose declarator has the form. & attr(optional) declarator. (1) && attr(optional) declarator.
There are two kinds of references: lvalue references which refer to a named variable and rvalue references which refer to a temporary object.
In C++03, it was not legal to do the following
typedef int &ref;
ref &r = ...; // reference to reference!
This frequently causes problems for people compiling with really strict or older C++03 compilers (GCC4.1 as well as Comeau 8/4/03 do not like the above) because the Standard function object binders do not take care of the "reference to reference" situation, and occasionally create such illegal types.
In C++0x this is called "reference collapsing", yes. Most current C++03 compilers do that (i.e a T&
where T
denotes a reference type is T
again), by retroactively applying the rule. The boost.call_traits library makes it easy to declare such function parameters though, so that the "reference to reference" situation does not occur.
Please note that the const
there does not have any effect. A const
applied on a reference type is silently ignored. So even if the compiler supports reference collapsing, the following is not legal
int const x = 0;
// illegal: trying to bind "int&" to "int const"!
ref const& r = x;
According to this, in C++98 there was only limited support for reference collapsing:
In C++98, there is only one reference collapsing rule: T& & or a reference to a reference, collapses to T&:
void g(int & ri) {++ri;} // int& & -> int&
void f(int & ri) {g(ri);}
Even there, it's illegal to try to declare a variable that is a reference to a reference:
int ben;
int& bill(ben); // OK
int & & bob(bill); // error C2529: 'bob' : reference to reference is illegal
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With