Структурированные привязки: когда что-то выглядит как ссылка и ведет себя аналогично ссылке, но это не ссылка
Вчера я видел интересный вопрос на 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);