Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - страница 13
представляет собой вывод типа шаблона. Но как это может быть? Вывод типа шаблона работает с шаблонами, функциями и параметрами, а >auto
не имеет дела ни с одной из этих сущностей.
Да, это так, но это не имеет значения. Существует прямая взаимосвязь между выводом типа шаблона и выводом типа >auto
. Существует буквальное алгоритмическое преобразование одного в другой.
В разделе 1.1 вывод типа шаблона пояснялся с использованием обобщенного шаблона функции
>template
>void f(ParamType param);
и обобщенного вызова
>f(expr); // Вызов f с некоторым выражением
При вызове >f
компиляторы используют >expr
для вывода типов >T
и >ParamType
.
Когда переменная объявлена с использованием ключевого слова >auto
, оно играет роль >Т
в шаблоне, а спецификатор типа переменной действует как >ParamType
. Это проще показать, чем описать, так что рассмотрим следующий пример:
>auto x = 27;
Здесь спецификатором типа для >x
является >auto
само по себе. С другой стороны, в объявлении
>const auto cx = x;
спецификатором типа является >const auto
. А в объявлении
>const auto& rx = x;
спецификатором типа является >const auto&
. Для вывода типов для >x
, >сх
и >rx
в приведенных примерах компилятор действует так, как если бы для каждого объявления имелся шаблон, а также вызов этого шаблона с соответствующим инициализирующим выражением:
>template
>void func_for_x(Т param); // вывода типа x
>func_for_x(27); // Концептуальный вызов: выве-
> // денный тип param является
> // типом x
>template
>void func_for_cx(const Т param); // вывода типа cx
>func_for_cx(x); // Концептуальный вызов: выве-
> // денный тип param является
> // типом cx
>template
>void func_for_rx(const T& param); // вывода типа rx
>func_for_rx(x); // Концептуальный вызов: выве-
> // денный тип param является
> // типом rx
Как я уже говорил, вывод типов для >auto
представляет собой (с одним исключением, которое мы вскоре рассмотрим) то же самое, что и вывод типов для шаблонов.
В разделе 1.1 вывод типов шаблонов был разделен на три случая, основанных на характеристиках >ParamType
, спецификаторе типа >param
в обобщенном шаблоне функции. В объявлении переменной с использованием >auto
спецификатор типа занимает место >ParamType
, так что у нас опять имеются три случая.
• Случай 1. Спецификатор типа представляет собой ссылку или указатель, но не универсальную ссылку.
• Случай 2. Спецификатор типа представляет собой универсальную ссылку.
• Случай 3. Спецификатор типа не является ни ссылкой, ни указателем. Мы уже встречались со случаями 1 и 3:
>auto x = 27; // Случай 3 (x не указатель и не ссылка)
>const auto cx = x; // Случай 3 (cx не указатель и не ссылка)
>const auto& rx = x; // Случай 1 (rx - неуниверсальная ссылка)
Случай 2 работает, как и ожидалось:
>auto&& uref1 = x; // x - int и lvalue, так что тип uref1 – int&
>auto&& uref2 = cx; // cx - const int и lvalue, так что тип
> // uref2 - const int&
>auto&& uref3 = 27; // 27 - int и rvalue, так что тип
> // uref3 - int&&
Раздел 1.1 завершился обсуждением того, как имена массивов и функций превращаются в указатели для спецификаторов типа, не являющихся ссылками. То же самое происходит и при выводе типа >auto
:
>const char name[] = // Тип name - const char [13]
> "R. N. Briggs";
>auto arr1 = name; // Тип arr1 - const char*
>auto& arr2 = name; // Тип arr2 - const char (&)[13]
>void someFunc(int, double); // someFunc - функция, ее тип
> // void(int, double)
>auto func1 = someFunc; // Тип func1 - void (*)(int, double)
>auto& func2 = someFunc; // Тип func2 - void (&)(int, double)
Как можно видеть, вывод типа >auto
работает подобно выводу типа шаблона. По сути это две стороны одной медали.