The following code shows that if a template taking a ref-to-const
parameter is instantiated with a reference type (e.g., int&
), the parameter isn't const
:
#include <iostream>
template<typename T>
void f(const T& arg) // arg isn't const if T is a reference type
{
arg = -1;
}
int main()
{
int x = 0;
f<int&>(x); // instantiate f with reference type
std::cout << x << '\n'; // prints -1 under gcc, clang, and msvc
}
What's going on here?
My guess is that the initial type of arg
is int & const &
and that this somehow transforms to int&
. If that's so, exactly how does that happen, in terms of the standard? If that's not what's going on, what is?
Thanks to Vlad from Moscow's answer to C++: template function with explicitly specified reference type as type parameter, I believe the crux of the const
-disappearance is [dcl.ref], which says:
In a declaration
T D
whereD
has either of the forms& attribute-specifier-seqopt D1
&& attribute-specifier-seqopt D1and the type of the identifier in the declaration
T D1
is “derived-declarator-type-listT
”, then the type of the identifier ofD
is “derived-declarator-type-list reference toT
.” The optional attribute-specifier-seq appertains to the reference type. Cv-qualified references are ill-formed except when the cv-qualifiers are introduced through the use of a typedef-name ([dcl.typedef], [temp.param]) or decltype-specifier ([dcl.type.simple]), in which case the cv-qualifiers are ignored.
I've emboldened the relevant text. (I'd like to format the entire paragraph as it is in the standard, but I can't figure out how to get the right indentation and to add subscripting.)
Once the const
disappears, normal reference collapsing kicks in as usual.
A const T
is a object of type T
whose value cannot be modified. However, when T
is a reference type, the const
modifier is superfluous since references cannot be changed once initialized - they always refer to the same object. Thus, a const T
when T=int&
is just a T
(which in this case is int&
). Thus, the argument that f<int&>
takes is a lvalue reference to an int&
, which by c++11's collapsing rules is just int&
.
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