auto sz = 0, pi = 3.14; //
const
и auto
Выводимый компилятором тип для спецификатора auto
не всегда точно совпадает с типом инициализатора. Компилятор корректирует тип так, чтобы он соответствовал обычным правилам инициализации.
Во-первых, как уже упоминалось, при использовании ссылки в действительности используется объект, на который она ссылается. В частности, при использовании ссылки как инициализатора им является соответствующий объект. Компилятор использует тип этого объекта для выведения типа auto
.
int i = 0, &r = i;
auto a = r; //
Во-вторых, выведение типа auto
обычно игнорирует спецификаторы const
верхнего уровня (см. раздел 2.4.3). Как обычно в инициализациях, спецификаторы const
нижнего уровня учитываются в случае, когда инициализатор является указателем на константу.
const int ci = i, &cr = ci;
auto b = ci; //
auto с = cr; //
//
auto d = &i //
auto e = &ci //
//
Если необходимо, чтобы у выведенного типа был спецификатор const
верхнего уровня, его следует указать явно.
const auto f = ci; //
Можно также указать, что необходима ссылка на автоматически выведенный тип. Обычные правила инициализации все еще применимы.
auto &g = ci; //
auto &h = 42; //
const auto &j = 42; //
Когда запрашивается ссылка на автоматически выведенный тип, спецификаторы const
верхнего уровня в инициализаторе не игнорируются. Как обычно при связывании ссылки с инициализатором, спецификаторы const
не относятся к верхнему уровню.
При определении нескольких переменных в том же операторе важно не забывать, что ссылка или указатель — это часть специфического оператора объявления, а не часть базового типа объявления. Как обычно, инициализаторы должны быть совместимы с автоматически выведенными типами:
auto k = ci, &l = i; //
auto &m = ci, *p = &ci //
//
//
auto &n = i, *p2 = &ci
Упражнение 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;
decltype
decltype
, возвращающий тип его операнда. Компилятор анализирует выражение и определяет его тип, но не вычисляет его результат.
decltype(f()) sum = x; //
//
Здесь компилятор не вызывает функцию f()
, но он использует тип, который возвратил бы такой вызов для переменной sum
. Таким образом, компилятор назначает переменной sum
тот же тип, который был бы возвращен при вызове функции f()
.