ядро языка · вывод типовcore language · type deduction

auto

Компилятор выводит тип переменной из инициализатора вместо того, чтобы ты писал его руками. Не «динамическая типизация» — тип фиксируется на этапе компиляции и не может измениться.The compiler deduces a variable's type from its initializer instead of you writing it out by hand. This is not "dynamic typing" — the type is fixed at compile time and can never change.

часто используетсяcommonly used нулевой рантайм-overheadzero runtime overhead

Что этоWhat it is

auto — ключевое слово, которое вместо явного типа заставляет компилятор вывести тип переменной из выражения-инициализатора по тем же правилам, что используются для вывода типов шаблонных параметров (template argument deduction).auto is a keyword that, instead of an explicit type, has the compiler deduce a variable's type from its initializer expression, following the same rules used for template argument deduction.

до C++11before C++11
std::map<std::string, std::vector<int>>::const_iterator it =
    m.find("key");

std::unique_ptr<Widget> w(new Widget());
с autowith auto
auto it = m.find("key");

auto w = std::make_unique<Widget>();

Зачем ввелиWhy it was introduced

Три независимые причины совпали в C++11:Three independent motivations converged in C++11:

01

Невыразимые вручную типыTypes that can't be spelled out by hand

Тип лямбды уникален и не имеет письменного обозначения — единственный способ сохранить лямбду в переменную (не через std::function, с overhead) — auto f = [](){...};.A lambda's type is unique and has no spellable name — the only way to store a lambda in a variable (without going through std::function, with its overhead) is auto f = [](){...};.

02

Многословные типы шаблоновVerbose template types

Итераторы контейнеров контейнеров, результаты bind, вложенные шаблоны — писать это руками не только долго, но и хрупко: тип меняется при рефакторинге сигнатуры, и его нужно менять во всех местах использования.Iterators of containers of containers, the result types of bind, nested templates — spelling these out by hand is not just tedious but fragile: the type changes whenever a signature is refactored, and every call site has to be updated in lockstep.

03

DRY-принцип для инициализацииThe DRY principle applied to initialization

auto x = compute(); — тип объявлен один раз (в сигнатуре compute()), а не дважды (в сигнатуре и в объявлении переменной). Меньше шанс на несовпадение типа и на неявное дорогое преобразование при инициализации.auto x = compute(); declares the type once (in the signature of compute()), rather than twice (in the signature and again in the variable declaration). That leaves less room for a type mismatch or a silent, expensive conversion at initialization.

Как это работает под капотомHow it works under the hood

Вывод типа для auto использует те же правила, что и для параметра шаблона T при вызове template<class T> void f(T param) — с одной оговоркой про {} (см. грабли ниже). Это происходит целиком на этапе компиляции: auto не порождает никакого рантайм-кода и не создаёт тип «переменного размера» — после компиляции переменная имеет ровно такой же машинный код, как если бы тип был написан явно.Type deduction for auto follows the same rules as for the template parameter T in a call to template<class T> void f(T param) — with one exception around {} (see the gotchas below). This all happens entirely at compile time: auto generates no runtime code and doesn't create some "variable-size" type — after compilation, the variable has exactly the same machine code as if the type had been written out explicitly.

Ключевое следствие правил вывода: auto по умолчанию отбрасывает ссылки и верхнеуровневый const/volatile у инициализатора, если явно не написать auto& / const auto& / auto&&:A key consequence of the deduction rules: auto strips references and top-level const/volatile from the initializer by default, unless you explicitly write auto& / const auto& / auto&&:

const int& cr = get_ref();
auto        a = cr;   // int        — const и & отброшены, будет копия// int        — const and & are dropped, this is a copy
auto&       b = cr;   // const int& — const сохранён, потому что явная ссылка// const int& — const is preserved because the reference is explicit
auto&&      c = cr;   // const int& — universal reference, см. rvalue-references.html// const int& — a universal reference, see rvalue-references.html

ГраблиGotchas

auto x = {1, 2, 3}; → std::initializer_list, не массивnot an array

Единственное расхождение с template deduction: auto с фигурными скобками выводит std::initializer_list<int>, а не int[3] и не единственный int. auto x = {1}; — тоже initializer_list<int> с одним элементом, не int — частый источник удивления.The one place auto diverges from template deduction: with brace-init, auto deduces std::initializer_list<int>, not int[3] and not a lone int. auto x = {1}; is also an initializer_list<int> with one element, not an int — a frequent source of surprise.

auto прячет дорогие неявные копииauto hides expensive implicit copies

auto row = table[i]; может незаметно скопировать тяжёлый объект, если operator[] возвращает по значению, а не по ссылке — тип не виден в объявлении, поэтому легко не заметить копирование. Смотреть сигнатуру возвращаемого типа, когда важна производительность.auto row = table[i]; can silently copy a heavy object if operator[] returns by value rather than by reference — the type isn't spelled out in the declaration, so the copy is easy to miss. Check the return type's signature whenever performance matters.

auto не читается сам по себеauto isn't self-documenting

В отличие от явного типа, auto требует смотреть на инициализатор, чтобы понять, что за тип у переменной — код с длинной цепочкой вызовов до auto x = a.b().c().d(); может быть менее самодокументируемым. Компенсируется хорошими именами переменных и IDE, которая покажет выведенный тип.Unlike an explicit type, auto requires looking at the initializer to figure out the variable's type — code with a long call chain like auto x = a.b().c().d(); can end up less self-documenting. This is compensated for by good variable names and an IDE that shows the deduced type on hover.