Спецификатор типа decltype

Задания раздела 2.5.3
2.36. Определите в следующем коде тип каждой переменной и значения, которое будет иметь каждая из них по завершении.
int a=3, b=4;
decltype(a) c=a;
deltype((b)) d=a;
++c;
++d;
2.37. Присвоение - это пример выражения, которое возвращает ссылочный тип. Тип - это ссылка на тип левого операнда. Таким образом, если переменная i имеет тип int, то выражение i=x имеет тип int&. С учетом этого определите тип и значение каждой переменной в следующем коде:
int a=3, b=4;
decltype(a) c=a;
decltype(a=b) d=a;
2.38. Опишите различия выведения типа спецификаторами decltype и auto. Приведите пример выражения, где спецификаторы auto и decltype выведут тот же тип, и пример, где они выведут разные типы.

p111_ex2-5-3

Автоопределение типа имеет еще одно лицо. Выглядит оно как decltype. Выражение decltype() анализирует выражение в скобках (ну не чудесно ли?) и выводит тип, не вычисляя значения этого выражения. Простыми словами - на глазок (весьма точный надо полагать) определяет тип, который нужен для последующей за выражением переменной:
decltype (f()) i=x; // i имеет тип, который возвращает функция f() (тип значения?)
Надо сказать, что компилятор не вызывает функцию, а просто использует тип (комплекс моей неполноценности перед компилятором скоро достигнет невероятных размеров).
В отличие от auto, которому всё равно на спецификатор const верхнего уровня, decltype всегда его учитывает.

const int ci=0; &cj=ci;
decltype (ci) x=0; // х типа const int;
decltype (cj) y=x; // y типа const int& и связан с х;
decltype (cj) z; /* так нельзя, потому что ссылка должна быть инициализирована */

Спецификатор decltype – единственный контекст, в котором переменная определена, поскольку ссылка не рассматривается как синоним объекта, на который она ссылается
После прочтения всей темы могу предположить, что здесь (в первой части предложения) говорится о выражении внутри скобок после decltype. То есть переменная внутри скобок используется как временный объект и на переменные вне их никак не влияет.

Если decltype применяют к выражению, которое не является переменной, то получаемый тип соответствует типу выражения.

decltype возвращает ссылочный тип, если полученный результат способен стоять слева от оператора присвоения (что бы это могло быть?)

int i=22, *p=&i, &r=i;
decltype (r+0) b; // b не инициализирована и имеет тип int
decltype (*p) c; // ошибка, потому что ссылка не инициализирована

c r+0 все более-менее понятно. r – ссылка, но decltype обращается к значению выражения r+0, которое уже не ссылка, а вполне конкретное число. Если бы стояло decltype (r) b, то переменная b имела бы ссылочный тип и её надо было бы инициализировать.

*p - простой указатель и содержит адрес переменной i. Утверждается, что переменная c имеет тип int&. p - указатель на переменную типа int, i – сама переменная типа int, а decltype (*p) c – ссылочный тип int&. Шикарно, определение переменных в C++ запутывает меня все сильнее.

И как апофеоз своим размышлениям (которые пытаются понять, что вообще здесь происходит), я читаю следующее:

Оператор обращения к значению – пример выражения, для которого спецификатор decltype возвращает ссылку. Кроме того, этому объекту можно присвоить значение. ТАКИМ ОБРАЗОМ (ненавижу это словосочетание), decltype (*p) выведет тип int& а не int. Все, точка. Просто правило языка C++. Выдохнул, расслабился.

А вот если сделать так: decltype (*p+0) то выводимый тип уже будет не ссылка.

#include <iostream>
int main ()
{
int i=22, *p=&i, &r=i;
decltype (r+0) b;
decltype (*p+2) c;
std::cout << p << " " << c << " "<< i;
return(0);
}
В выводе i осталось равным 22.
Так же в decltype() можно навернуть скобок. Если скобки в скобках, то decltype вернет ссылочный тип, если скобки только внешние - то тип переменной в скобках.

int i=22;
decltype ((i)) d; // d – int& и должна быть инициализирована
decltype (i) e; // e - int

 

2.36. Определите в следующем коде тип каждой переменной и значения, которое будет иметь каждая из них по завершении.
int a=3, b=4;
decltype(a) c=a;
deltype((b)) d=a;
++c;
++d;

int a=3, b=4;
decltype(a) c=a; // int c=a (c=3)
decltype((b)) d=a;// int& d=a;
++c; // c=3+1
++d; //d - ссылка на a, a=3+1
Ответ: a=4, b=4, c=4

2.37. Присвоение - это пример выражения, которое возвращает ссылочный тип. Тип - это ссылка на тип левого операнда. Таким образом, если переменная i имеет тип int, то выражение i=x имеет тип int&. С учетом этого определите тип и значение каждой переменной в следующем коде:
int a=3, b=4;
decltype(a) c=a;
decltype(a=b) d=a;

int a=3, b=4;
decltype(a) c=a; // int c=a; (c=3)
decltype(a=b) d=a; // int& d=a; (d ссылка на a)
Вопрос наверное был в том, смогу ли я определить, изменяет ли выражение в скобках decltype значение переменной a. Хорошая попытка, но нет. Я уже проверил ранее.

2.38. Опишите различия выведения типа спецификаторами decltype и auto. Приведите пример выражения, где спецификаторы auto и decltype выведут тот же тип, и пример, где они выведут разные типы.

decltype не игнорирует const верхнего уровня, а auto игнорирует. Одного этого достаточно, чтобы ответить на вопрос задания.

#include <iostream>
int main ()
{
const int ko=1024;
auto f=ko;
f=22;
decltype (ko) f2=42;
f2=11; // ошибка, f2 константа, менять ей нельзя
std::cout << f << " "<< f2;
return(0);
}
Объекты типа auto должны быть инициализированы всегда, а при определении типа с помощью decltype - нет.
Ну и на правах оффтопа. Очень радует то, что тип auto не лепит ко всем непонятным выражениям ссылочный тип, а decltype хлебом не корми - дай поссылаться.

Добавить комментарий