Разве невозможно достичь того же результата без явного объявления переменной auto
?
Я собираюсь немного перефразировать ваш вопрос таким образом, чтобы помочь вам понять, почемувам нужно auto
:
Разве невозможно достичь того же результата без явного с использованием заполнителя типа ?
Разве это не возможно ?Конечно, это было «возможно».Вопрос в том, стоило ли бы это сделать.
Большинство синтаксисов в других языках, которые не имеют типовых имен, работают одним из двух способов.Есть Go-подобный способ, где name := value;
объявляет переменную.И есть Python-подобный способ, где name = value;
объявляет новую переменную, если name
ранее не был объявлен.
Давайте предположим, что нет никаких синтаксических проблем с применением любого синтаксиса к C ++ (хотя яУже видно, что identifier
, за которым следует :
в C ++, означает «сделать ярлык»).Итак, что вы теряете по сравнению с заполнителями?
Ну, я больше не могу этого делать:
auto &name = get<0>(some_tuple);
Видите, auto
всегда означает "значение".Если вы хотите получить ссылку, вам нужно явно использовать &
.И он по ошибке не сможет скомпилироваться, если выражение присваивания является prvalue.Ни один из синтаксисов, основанных на присваивании, не имеет возможности различать ссылки и значения.
Теперь вы можете сделать так, чтобы такие синтаксисы присваивания выводили ссылки, если данное значение является ссылкой.Но это будет означать, что вы не можете делать:
auto name = get<0>(some_tuple);
Это копирует из кортежа, создавая объект, независимый от some_tuple
.Иногда это именно то, что вы хотите.Это еще более полезно, если вы хотите перейти от кортежа с помощью auto name = get<0>(std::move(some_tuple));
.
ОК, поэтому, возможно, мы могли бы немного расширить эти синтаксисы, чтобы учесть это различие.Может быть, &name := value;
или &name = value;
означало бы выводить ссылку типа auto&
.
ОК, хорошо.Как насчет этого:
decltype(auto) name = some_thing();
О, верно;C ++ на самом деле имеет два заполнителя: auto
и decltype(auto)
.Основная идея этого вывода заключается в том, что он работает точно так же, как если бы вы сделали decltype(expr) name = expr;
.Так что в нашем случае, если some_thing()
является объектом, он выведет объект.Если some_thing()
является ссылкой, она выведет ссылку.
Это очень полезно, когда вы работаете с шаблоном кода и точно не знаете, каким будет возвращаемое значение функции.Это отлично подходит для пересылки и является важным инструментом, даже если он не используется широко.
Так что теперь нам нужно добавить больше к нашему синтаксису.name ::= value;
означает «делать то, что decltype(auto)
делает».У меня нет эквивалента для варианта Pythonic.
Глядя на этот синтаксис, не так ли легко случайно набрать неверно?Мало того, это вряд ли самодокументируется.Даже если вы никогда раньше не видели decltype(auto)
, он достаточно большой и очевидный, чтобы вы могли хотя бы легко сказать, что происходит что-то особенное.Принимая во внимание, что визуальная разница между ::=
и :=
минимальна.
Но это вещи мнения;Есть более существенные вопросы.Видите, все это основано на использовании синтаксиса присваивания.Ну ... как насчет мест, где вы не можете использовать синтаксис присваивания?Вот так:
for(auto &x : container)
Меняем ли мы это на for(&x := container)
?Потому что это, кажется, говорит что-то очень отличное от основанного на диапазоне for
.Похоже, это оператор инициализатора из обычного цикла for
, а не из диапазона for
.Это также будет отличаться синтаксисом от невысказанных случаев.
Кроме того, инициализация копирования (с использованием =
) не то же самое в C ++, что и прямая инициализация (использование синтаксиса конструктора).Таким образом, name := value;
может не работать в случаях, когда auto name(value)
имел бы.
Конечно, вы могли бы объявить, что :=
будет использовать прямую инициализацию, но это было бы совершенно несовместимо с тем, как остальныеC ++ ведет себя.
Также есть еще одна вещь: C ++ 14.Это дало нам одну полезную функцию вывода: вывод типа возврата.Но это основано на заполнителях.Так же, как основанный на диапазоне for
, он основывается на типе имени, которое заполняется компилятором, а не на некотором синтаксисе, применяемом к определенному имени и выражению.
Видите, все эти проблемы возникаютиз того же источника: вы изобретаете совершенно новый синтаксис для объявления переменных.Объявления на основе заполнителей не должны были придумывать новый синтаксис .Они используют тот же синтаксис, что и раньше;они просто используют новое ключевое слово, которое действует как тип, но имеет особое значение.Это то, что позволяет ему работать на основе диапазона for
и для вычета типа возврата.Это то, что позволяет ему иметь несколько форм (auto
против decltype(auto)
).И т. Д.
Заполнители работают, потому что они являются простейшим решением проблемы, сохраняя при этом все преимущества и универсальность использования фактического имени типа.Если вы придумали другую альтернативу, которая работала бы так же универсально, как и заполнители, очень маловероятно, что она будет такой же простой, как заполнители.
Если только это не было просто написание заполнителей с разными ключевыми словами или символами ...