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.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;
2.5.3. Спецификатор типа decltype
Иногда необходимо определить переменную, тип которой компилятор выводит из выражения, но не использовать это выражение для инициализации переменной. Для таких случаев новый стандарт вводит спецификатор типа decltype
, возвращающий тип его операнда. Компилятор анализирует выражение и определяет его тип, но не вычисляет его результат.
decltype(f()) sum = x; // sum имеет тот тип,
// который возвращает функция f
Здесь компилятор не вызывает функцию f()
, но он использует тип, который возвратил бы такой вызов для переменной sum
. Таким образом, компилятор назначает переменной sum
тот же тип, который был бы возвращен при вызове функции f()
.
Таким образом, спецификатор decltype
учитывает спецификатор const
верхнего уровня и ссылки, но несколько отличается от того, как работает спецификатор auto
. Когда выражение, к которому применен спецификатор decltype
, является переменной, он возвращает тип этой переменной, включая спецификатор const
верхнего уровня и ссылки.
const int ci = 0, &cj = ci;
decltype(ci) x = 0; // x имеет тип const int
decltype(cj) y = x; // y имеет тип const int& и связана с x
decltype(сj) z; // ошибка: z - ссылка, она должна быть инициализирована
Поскольку cj
— ссылка, decltype (cj)
— ссылочный тип. Как и любую другую ссылку, ссылку z
следует инициализировать.
Следует заметить, что спецификатор decltype
— единственный контекст, в котором переменная определена, поскольку ссылка не рассматривается как синоним объекта, на который она ссылается.
decltype
и ссылкиКогда спецификатор decltype
применяется к выражению, которое не является переменной, получаемый тип соответствует типу выражения. Как будет продемонстрировано в разделе 4.1.1, некоторые выражения заставят спецификатор decltype
возвращать ссылочный тип. По правде говоря, спецификатор decltype
возвращает ссылочный тип для выражений, результатом которых являются объекты, способные стоять слева от оператора присвоения.
// decltype выражение может быть ссылочным типом
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; // ok: сложение возвращает тип int; b имеет тип int
// (не инициализирована)
decltype(*p) с; // ошибка: с имеет тип int& и требует инициализации
Здесь r
— ссылка, поэтому decltype(r)
возвращает ссылочный тип. Если необходим тип, на который ссылается ссылка r
, можно использовать ее в таком выражении, как r + 0
, поскольку оно возвращает значение не ссылочного типа.