Reference collapsing? [duplicate]
Asked Answered
D

2

17

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?

Decolonize answered 22/9, 2010 at 16:2 Comment(2)
+1. I have some homework to do on this, thxHypersonic
I would like to link this similar question: #4144734Hurty
I
20

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; 
Iceland answered 22/9, 2010 at 18:0 Comment(3)
Great, I figured out this could be solved by traits classes, but I have never seen any such thing in [my implementation of] STL.Decolonize
Shouldn't that be "i.e. a T& where T denotes a reference type is T& again"?Maclaine
@Fred that would be self-recursive. I mean, if T is U&, and you say T&, the result type is T - i.e U&. Of course, this is not compatible with rvalue references. I would need to say "i.e a T& where T denotes a type U &-or-&& denotes the type U &", to be correct with rvalue refs.Iceland
H
5

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
Hypersonic answered 22/9, 2010 at 16:21 Comment(5)
There is no reference collapsing in C++03. The author of that article is misguided. The type of an identity-expression using the name of a reference is not a reference type. No expression has reference type. Expressions have value categories which decide how they may bind to references.Clockmaker
@Clockmaker - thanks, and also there are better references now. I'll delete this part.Hypersonic
Thanks… but hmm, that link isn't the one I followed before.Clockmaker
@Clockmaker - I removed a link to MSDN that had refs to C++03Hypersonic
The link you removed isn't the one I was referring to in the first comment. The example is mistaken; the function call g( ri ) doesn't involve any sort of collapsing.Clockmaker

© 2022 - 2024 — McMap. All rights reserved.