Что означает синтаксис auto [, ] и почему он не работает с { }

Я всегда думал, что auto в C++17 является заполнителем для фактического типа данных, но в следующем примере это не так:

tuple<int, int> permute(int a, int b){return {b,a};}
int main(){
   auto [x,y] = permute(2,5);
   cout<<x<<","<<y<<endl;
   tuple<int, int> {x,y} = permute(2,5);
   cout<<x<<","<<y<<endl;
   return 0;
   }

Почему auto требует [ , ], а для кортежа требуются фигурные скобки?

Обновлено: Как указано ниже, это объявление структурированной привязки C++17. Тем не менее, у меня остается вопрос: почему я не могу заменить [ , ] на tuple<int, int> {x,y}?

Вы уверены, что это для C++11. Представлен C++17 Объявление структурированной привязки вживую - godbolt.org/z/15KKEx84v

Richard Critten 02.08.2024 20:05

Что касается редактирования: строка tuple<int, int> {x,y} = permute(2,5); ничего не делает и является ошибкой.

ALX23z 02.08.2024 21:05

автоматический тип в C++17 не заменяется фактическим типом? Это работает: tuple<int, int> z = premute(2, 5); В структурированной привязке auto требуется синтаксической грамматикой. Или вы можете использовать int x; int y; std::tie(x, y) = permute(2, 5);.

Eljay 02.08.2024 22:49

«почему я не могу заменить tuple<int, int> {x,y} на auto {x,y}?...» Потому что это привязка структуры, которая не позволяет { }. Что такое синтаксис автоматического списка в квадратных скобках?

user12002570 03.08.2024 08:35

«почему я не могу заменить tuple<int, int> {x,y} на auto {x,y} ?...» Почему структурированные привязки C++17 не используют { }?

user12002570 03.08.2024 08:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
158
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

auto [/*...*/] — это синтаксическая конструкция, совершенно отличная от других объявлений (и она поддерживается только начиная с C++17, кстати).

Это так называемая структурированная привязка, а не простое объявление переменной. Ключевое слово auto и скобки являются частью этого специального синтаксиса. Они не являются (напрямую) типом объявляемой переменной или инициализатором такой переменной.

auto используется в поведении объявления структурированной привязки для предоставления объявления (безымянной) переменной, которая инициализируется с правой стороны, как если бы:

auto _unnamed = permute(2,5);

В вашем примере auto будет выведено до std::tuple<int,int>. x и y тогда ведут себя как ссылки на первый и второй элемент этой переменной _unnamed.

Структурированная привязка по своей сути не имеет никакой связи с std::tuple. Любой тип массива, агрегатный тип или тип, предоставляющий определенный интерфейс std::tuple_element/std::get, можно использовать со структурированными привязками.

Что касается того, почему указание явного типа напрямую вместо auto в этой форме объявления не допускается, единственная причина, приведенная в предложении в разделе 3.6, заключается в том, что всегда можно явно указать тип в правой части, если желанный:

 auto [x,y] = tuple<int,int>(permute(2,5));

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


В tuple<int, int> {x,y} фигурные скобки являются инициализатором объекта, а именно временного объекта типа tuple<int, int>, создаваемого в этом выражении.

Обратите внимание, что это вовсе не декларация. Он использует x и y из предыдущего объявления структурированной привязки для инициализации временного объекта. Он не объявляет x или y. Затем вы присваиваете результат permute() этому временному объекту, который фактически ничего не делает, поскольку этот объект немедленно уничтожается в конце выражения.

Простое объявление будет выглядеть так:

tuple<int, int> t = permute(2,5);

Это не позволит напрямую обращаться к элементам по их собственным именам. Вам придется ввести для них имена в качестве ссылок, особенно если вы не используете синтаксис структурированной привязки:

int& x = std::get<0>(t);
int& y = std::get<1>(t);

почему я не могу заменить tuple<int, int> {x,y} на auto {x,y}?

std::tuple ни в коем случае не является особым типом в C++. Тот факт, что вы используете фигурные скобки, не означает, что вы хотите сформировать кортеж. Вы можете написать S{x,y} для любого подходящего типа агрегата S. Было бы странно, если бы язык предпочитал tuple другим возможным типам.

Во многих других языках тип кортежа — это не только библиотечный тип, как в C++, но более фундаментально связан с основным языком. В этом случае язык обычно предоставляет специальный синтаксис для формирования кортежей, например как (x, y). В C++ кортежи не являются встроенными типами, не имеют специального значения в базовом языке, и для них не существует специального синтаксиса.

Однако можно написать tuple{x,y}. Типы элементов можно вывести с помощью CTAD (вывод аргументов шаблона класса), начиная с C++17.

При этом в стандартной библиотеке действительно есть специальный тип, который предпочтительнее при использовании фигурных скобок (и можно спорить о том, было ли это хорошим решением спроектировать его таким образом). Однако этот предпочтительный тип — это не std::tuple, а std::initializer_list, который представляет собой магический тип, который ведет себя аналогично копируемой ссылке на неявно созданный массив, т. е. он работает только с однородными типами элементов и не обеспечивает семантику значений. при копировании.

Так, например, в этом коде:

auto a = {x, y};

Тип a будет выведен в std::initializer_list<int>. Это предназначено в первую очередь для итерации в циклах range-for и для передачи конструкторам контейнеров. Итак, даже если предпочтение одного типа другому в любом случае не было странным, C++ уже сделал выбор в пользу другого типа, кроме std::tuple.

Вот почему, например, в C# есть специальный синтаксис для кортежей (a, b), тип которых выводит (и целевые типы) к очень конкретному типу (ValueTuple<...>).

Blindy 02.08.2024 20:27

Другие вопросы по теме