Эффективный и современный С++. 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 работает подобно выводу типа шаблона. По сути это две стороны одной медали.