The following code snippet is excerpted from cppref:
std::tuple<int, int&> f();
auto [x, y] = f();
// decltype(x) is int
// decltype(y) is int&
const auto [z, w] = f();
// decltype(z) is const int
// decltype(w) is int&
My question is at the last line:
Why is decltype(w)
int&
rather than const int&
?
Jarod42 answered the question the question in the comments, let me just cite the relevant part of the standard here, from [dcl.struct.bind]¹:
Given the type Ti designated by std::tuple_element::type, variables are introduced with unique names ri of type “reference to Ti” initialized with the initializer ([dcl.init.ref]), where the reference is an lvalue reference if the initializer is an lvalue and an rvalue reference otherwise. Each vi is the name of an lvalue of type Ti that refers to the object bound to ri; the referenced type is Ti.
Hence in const auto [z, w] = f();
, you have const T1
with T1
being int
and const T2
with T2
being int&
. As const
modifies what's on its left, this becomes int& const
and results in int&
.
Note that int& const
becoming int&
is only possible in template argument substitution, i.e., this won't compile:
int n = 42;
int& const doesntWork = n; // Error: 'const' qualifiers cannot be applied to 'int&'
but this does:
template <class T> void f(const T t)
{
++t;
}
int n = 42;
f<int&>(n);
where the identical contraction from int& const
to int&
as above takes place.
¹ Thanks to @cpplearner for pointing me to the exact paragraph here.
It would be the reference itself rather than the referenced value that would be const. As references aren't modifiable anyway there is no such thing as a constant reference.
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