Я всегда думал, что 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}
?
Что касается редактирования: строка tuple<int, int> {x,y} = permute(2,5);
ничего не делает и является ошибкой.
автоматический тип в C++17 не заменяется фактическим типом? Это работает: tuple<int, int> z = premute(2, 5);
В структурированной привязке auto
требуется синтаксической грамматикой. Или вы можете использовать int x; int y; std::tie(x, y) = permute(2, 5);
.
«почему я не могу заменить tuple<int, int> {x,y} на auto {x,y}?...» Потому что это привязка структуры, которая не позволяет { }
. Что такое синтаксис автоматического списка в квадратных скобках?
«почему я не могу заменить tuple<int, int> {x,y} на auto {x,y} ?...» Почему структурированные привязки C++17 не используют { }?
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<...>
).
Вы уверены, что это для C++11. Представлен C++17 Объявление структурированной привязки вживую - godbolt.org/z/15KKEx84v