Читать «Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14» онлайн - страница 18

Скотт Мейерс

const auto& rx = x;

спецификатором типа является const auto&. Для вывода типов для x, сх и rx в приведенных примерах компилятор действует так, как если бы для каждого объявления имелся шаблон, а также вызов этого шаблона с соответствующим инициализирующим выражением:

template<typename Т>              // Концептуальный шаблон для

void func_for_x(Т param);         // вывода типа x

func_for_x(27);                   // Концептуальный вызов: выве-

                                  // денный тип param является

                                  // типом x

template<typename Т>              // Концептуальный шаблон для

void func_for_cx(const Т param);  // вывода типа cx

func_for_cx(x);                   // Концептуальный вызов: выве-

                                  // денный тип param является

                                  // типом cx

template<typename Т>              // Концептуальный шаблон для

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)