Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does "const auto [x, y]" not behave as expected when binding to reference types?

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&?

like image 746
xmllmx Avatar asked Aug 07 '18 06:08

xmllmx


2 Answers

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.

like image 60
lubgr Avatar answered Oct 23 '22 23:10

lubgr


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.

like image 25
Alan Birtles Avatar answered Oct 24 '22 00:10

Alan Birtles