Except you can't have a "T & const". Based on a quick compiler experiment, it seems the attempt to do so will discard the const if it is created as the result of a typedef or similar, and error out if expressed directly.
Printable View
Good point. I didn't think that through. It doesn't make sense to say int & const x, since you can't make x "point" to a different object with or without the const. Since references must be initialized and cannot be reassigned, they are essentially const (in that sense) already.
That reasoning would make sense with const, but volitile is dropped the same way. The real story is that there are rules which fold cv-qualified reference into actual unqualified references. It may, however, explain the C++ committee's rational for this.
Since a reference is (in a sense) just another name for an object, it perhaps doesn't make sense for the reference itself to be volatile, but only for the object to be.
Yet this is allowed:
And then there's this case:Code:typedef int & T;
void foo (volatile T ref_to_non_volatile){
}
A more common case where these rules are needed is when T is a template specified type.Code:typedef int & T;
void foo (volatile T & same_type_as_above){
}
So, unless I'm missing something, your example is a reference to a volatile int, not a reference to a non-volatile.Code:// But this
typedef int & T;
void foo(volatile T x) { }
// is actually this
void foo(volatile int & x) { }
// not this
void foo(int & volatile x) { }
O_oQuote:
Yet this is allowed:
Not in the way you are suggestion as in response to oogabooga or his comments.
In both of those cases, `T' is treated as being simply `int &' type; in every way, the reference itself isn't `volatile'.
Furthermore, some compilers will allow it without warning; some compilers will allow it always producing a warning; some compilers will not allow it showing an error.
The problems related to producing a potentially "cv-modified" reference or "reference to a reference" is actually why you need "meta-functions" such as `add_const', `add_volatile', `remove_const', `remove_volatile', `add_reference', and `remove_reference'.
For example, the second bit of code fails under several versions of "MSVC", "BCC", and "ECC". (The error relates to "reference to reference is illegal" in general.) To further complicate the issue, the nature or the error depends on how `T' is formed. (In other words, a `T' formed from explicit template, inherited template, or standard traits all chance the error text.) You also have weird issues with overloading errors on some compilers.
Soma
O_oQuote:
Code:// But this
typedef int & T;
void foo(volatile T x) { }
// is actually this
void foo(volatile int & x) { }
// not this
void foo(int & volatile x) { }
I was afraid of that.
*sigh*
I didn't get here in time.
(Note: This code segment should actually always produce an error because the same function is being defined twice.)Code:// But this
typedef int & T;
void foo(volatile T x) { }
// is actually this
void foo(int & x) { }
That is, of course, when compilers allow the construct without error.
Where these will actually overload, the resolution depends on the "volatility" of the underlying object.Code:// this
void foo(int & x) { }
// is a different beast thant
void foo(volatile int & x) { }
SomaCode:int f1;
foo(f1);
volatile int f2;
foo(f2);
Nope. This is easier to show with const:
Volatile follows the same rule as const.Code:typedef int & T;
void foo(const T &x) {
x++; //modifies x, so x is not const. x is just and int &.
}
"T" is "int &", so "const T &" should be "int & const &", but that folds to "int &". Likewise with "volatile T &", with the same "T", should be "int & volatile &" but also folds to "int &".
EDIT: Clarified as per phantomotap's objection.
->Quote:
"T" is "int &", so "const T &" should be "int & const &", but that folds to "int &". Likewise with "volatile T &" folds to "int &".
Please, please fix that if you get a chance.Quote:
"T" is "int &", so "const T &" should be "int & const &", but that folds to "int &". Likewise with "volatile T &" as "int & volatile &", "volatile T &" folds to "int &".
Soma
Hmmmm, this is more complicated than I thought....
O_oQuote:
I didn't mention the intermediate step of "int & volatile &", but what I said is not wrong.
I didn't say it was wrong.
I implied it is vague, and it is vague because you like the specificity of the underlying type being a reference.
Without that context, the statement is wrong.
Soma
O_oQuote:
I'm pretty sure that MSVE BCC and ECC are wrong here, and the standard does allow this code, just as the compiler I tested on does.
Indeed. I had not intended to imply otherwise.
My only intent in providing that information was that anyone actually needing the exact details related to this discussion will necessarily find the related "real world" information useful.
[Edit]
Also, a better bit from the standard would be 8.3.2.6, I think, which spells out both the "reference to reference" aspect and the "cv-modifier" aspect in a single example.
[/Edit]
Soma