Почему "const auto [x, y]" не ведет себя так, как ожидалось при привязке к ссылочным типам?

Следующий фрагмент кода вычитается из 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&

Мой вопрос находится на последней строке:

Почему decltype(w) int& вместо const int& ?

Ответ 1

Jarod42 ответил на вопрос в комментариях, позвольте мне просто привести соответствующую часть стандарта здесь, из [dcl.struct.bind] ¹:

Учитывая тип Ti, обозначенный типом std :: tuple_element ::, вводятся переменные с уникальными именами ri типа "ссылка на Ti", инициализированным инициализатором ([dcl.init.ref]), где ссылка ссылка lvalue, если инициализатор является значением lvalue и ссылкой rvalue в противном случае. Каждое vi является именем lvalue типа Ti, которое ссылается на объект, связанный с ri; ссылочным типом является Ti.

Следовательно, в const auto [z, w] = f(); , у вас есть const T1 где T1 есть int и const T2 а T2 - int&. Поскольку const изменяет то, что слева от него, это становится int& const и приводит к int&.

Обратите внимание, что int& const становится int& возможно только при замене аргумента шаблона, т.е. Это не будет компилироваться:

int n = 42;
int& const doesntWork = n; // Error: 'const' qualifiers cannot be applied to 'int&'

но это делает:

template <class T> void f(const T t)
{
   ++t;
}

int n = 42;

f<int&>(n);

где происходит идентичное сокращение от int& const до int& как указано выше.

¹ Спасибо @cpplearner за то, что вы указали мне точный параграф.

Ответ 2

Это будет сама ссылка, а не ссылочная ценность, которая будет const. Поскольку ссылки не изменяются, в любом случае нет такой вещи, как постоянная ссылка.