Структурированные привязки: когда что-то выглядит как ссылка и ведет себя аналогично ссылке, но это не ссылка

Вчера я видел интересный вопрос на SO о структурированном связывании.
Мы можем подвести итог следующим образом. Рассмотрим пример кода ниже:

#include <tuple>
#include <type_traits>

int main() {
    auto tup = std::make_tuple(1, 2);
    auto & [ a, b ] = tup;
    // the following line won't compile for a isn't a reference
    // static_assert(std::is_reference_v<decltype(a)>);
}

В этом случае decltype(a) является int (вероятно) из-за этой пули (рабочий проект):

если e это не заключенное в скобки id-выражение, обозначающее структурированную привязку [...], decltype(e) ссылочный тип, указанный в спецификации объявления структурированной привязки

Вот фрагмент кода на wandbox, предоставленный @Curious в комментариях для тех, кто заинтересован. Это показывает, что на самом деле a не ссылка, не более того.
Пока что хорошо для первоначального вопроса, OP спросил, почему это было int вместо int & и стандарт говорит, что это выглядело как приемлемый ответ.

В любом случае, я хотел бы знать, почему комитет так решил. В конце дня, a относится к элементу в кортеже, и я могу изменить этот элемент через a, Другими словами, декларация a выглядит как ссылка, ведет себя аналогично ссылке, но это не ссылка.

Я могу жить с этим, но я хотел бы знать, каковы причины этого. Зачем decltype(a) не может быть просто int &? Есть ли значимая причина, которую может понять профан?

2 ответа

Решение

Я написал это вчера:

decltype(x), где x является структурированной привязкой, называет ссылочный тип этой структурированной привязки. В случае кортежа это тип, возвращаемый std::tuple_element, который не может быть ссылкой, даже если само структурированное связывание фактически всегда является ссылкой в ​​этом случае. Это эффективно имитирует поведение привязки к структуре, чьи нестатические члены данных имеют типы, возвращаемые tuple_elementсо ссылкой на саму привязку, являющуюся простой деталью реализации.

Эта тема была рассмотрена ранее (посмотрите в теге structd-bindings), а поведение, о котором вы говорите, даже рассматривается во втором ответе. Однако обоснование изложено в разделе 3.5 документа p0144r2:

Должен ли синтаксис быть расширен для const/&-квалификация отдельных типов имен?

Например:

auto [&x, const y, const& z] = f(); // NOT proposed

Мы думаем, что ответ должен быть нет. Это простая функция для хранения значения и привязки имен к его компонентам, а не для объявления нескольких переменных. Разрешение такой квалификации будет ползучестью, расширение функции будет чем-то другим, а именно способом объявления нескольких переменных.

Если мы хотим объявить несколько переменных, у нас уже есть способ записать это:

 auto val    = f();
 T& x        = get<0>(val);
 T2 const y  = get<1>(val);
 T3 const& z = get<2>(val);
Другие вопросы по тегам