2.5.2. Спецификатор типа auto
// тип item выводится из типа результата суммы val1 и val2
auto item = val1 + val2; // item инициализируется результатом val1 + val2
Здесь компилятор выведет тип переменной item из типа значения, возвращенного при применении оператора + к переменным val1 и val2. Если переменные val1 и val2 — объекты класса Sales_item (см. раздел 1.5), типом переменной item будет класс Sales_item. Если эти переменные имеют тип double, то у переменной item будет тип double и т.д.
Подобно любому другому спецификатору типа, используя спецификатор auto, можно определить несколько переменных. Поскольку объявление может задействовать только один базовый тип, у инициализаторов всех переменных в объявлении должны быть типы, совместимые друг с другом.
auto i = 0, *p = &i; // ok: i - int, а p - указатель на int
auto sz = 0, pi = 3.14; // ошибка: несовместимые типы у sz и pi
Составные типы, const и auto
Выводимый компилятором тип для спецификатора auto не всегда точно совпадает с типом инициализатора. Компилятор корректирует тип так, чтобы он соответствовал обычным правилам инициализации.
Во-первых, как уже упоминалось, при использовании ссылки в действительности используется объект, на который она ссылается. В частности, при использовании ссылки как инициализатора им является соответствующий объект. Компилятор использует тип этого объекта для выведения типа auto.
int i = 0, &r = i;
auto a = r; // a - int (r - псевдоним для i, имеющий тип int)
Во-вторых, выведение типа auto обычно игнорирует спецификаторы const верхнего уровня (см. раздел 2.4.3). Как обычно в инициализациях, спецификаторы const нижнего уровня учитываются в случае, когда инициализатор является указателем на константу.
const int ci = i, &cr = ci;
auto b = ci; // b - int (const верхнего уровня в ci отброшен)
auto с = cr; // с - int (cr - псевдоним для ci с const верхнего
// уровня)
auto d = &i; // d - int* (& объекта int - int*)
auto e = &ci; // e - const int* (& константного объекта - const нижнего
// уровня)
Если необходимо, чтобы у выведенного типа был спецификатор const верхнего уровня, его следует указать явно.
const auto f = ci; // выведенный тип ci - int; тип f - const int
Можно также указать, что необходима ссылка на автоматически выведенный тип. Обычные правила инициализации все еще применимы.
auto &g = ci; // g - const int&, связанный с ci
auto &h = 42; // ошибка: нельзя связать простую ссылку с литералом
const auto &j = 42; // ok: константную ссылку с литералом связать можно
Когда запрашивается ссылка на автоматически выведенный тип, спецификаторы const верхнего уровня в инициализаторе не игнорируются. Как обычно при связывании ссылки с инициализатором, спецификаторы const не относятся к верхнему уровню.
При определении нескольких переменных в том же операторе важно не забывать, что ссылка или указатель — это часть специфического оператора объявления, а не часть базового типа объявления. Как обычно, инициализаторы должны быть совместимы с автоматически выведенными типами:
auto k = ci, &l = i; // k - int; l - int&
auto &m = ci, *p = &ci; // m - const int&; p - указатель на const int
// ошибка: выведение типа из i - int;
// тип, выведенный из &ci - const int
auto &n = i, *p2 = &ci;
Упражнения раздела 2.5.2
Упражнение 2.33. С учетом определения переменных из этого раздела укажите то, что происходит в каждом из этих присвоений.
а = 42; b = 42; с = 42;
d = 42; е = 42; g = 42;
Упражнение 2.34. Напишите программу, содержащую переменные и присвоения из предыдущего упражнения. Выведите значения переменных до и после присвоений, чтобы проверить правильность предположений в предыдущем упражнении. Если они неправильны, изучите примеры еще раз и выясните, что привело к неправильному заключению.
Упражнение 2.35. Укажите типы, выведенные в каждом из следующих определений. Затем напишите программу, чтобы убедиться в своей правоте.
const int i = 42;
auto j = i; const auto &k = i; auto *p = &i;
const auto j2 = i, &k2 = i;