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

Скотт Мейерс

void f1(Т param);           // В f1 param передается по значению

template<typename Т>

void f2(T& param);          // В f2 param передается по ссылке

f1(someFunc);               // param выводится как указатель на

                            // функцию; тип - void (*)(int, double)

f2(someFunc);               // param выводится как ссылка на

                            // функцию; тип - void(&)(int,double)

Это редко приводит к каким-то отличиям на практике, но если вы знаете о преобразовании массивов в указатели, то разберетесь и в преобразовании функций в указатели.

Итак, у нас есть правила для вывода типов шаблонов, связанные с auto. В начале я заметил, что они достаточно просты, и по большей части так оно и есть. Немного усложняет жизнь отдельное рассмотрение согласованных lvalue при выводе типов для универсальных ссылок, да еще несколько “мутят воду” правила преобразования в указатели для массивов и функций. Иногда так и хочется, разозлившись, схватить компилятор и вытрясти из него — “А скажи-ка, любезный, какой же тип ты выводишь?” Когда это произойдет, обратитесь к разделу 1.4, поскольку он посвящен тому, как уговорить компилятор это сделать.

Следует запомнить

• В процессе вывода типа шаблона аргументы, являющиеся ссылками, рассматриваются как ссылками не являющиеся, т.е. их “ссылочность” игнорируется.

• При выводе типов для параметров, являющихся универсальными ссылками, lvalue-apгумeнты рассматриваются специальным образом.

• При выводе типов для параметров, передаваемых по значению, аргументы, объявленные как const и/или volatile, рассматриваются как не являющиеся ни const, ни volatile.

• В процессе вывода типа шаблона аргументы, являющиеся именами массивов или функций, преобразуются в указатели, если только они не использованы для инициализации ссылок.

1.2. Вывод типа auto

Если вы прочли раздел 1.1 о выводе типов шаблонов, вы знаете почти все, что следует знать о выводе типа auto, поскольку за одним любопытным исключением вывод типа auto представляет собой вывод типа шаблона. Но как это может быть? Вывод типа шаблона работает с шаблонами, функциями и параметрами, а auto не имеет дела ни с одной из этих сущностей.

Да, это так, но это не имеет значения. Существует прямая взаимосвязь между выводом типа шаблона и выводом типа auto. Существует буквальное алгоритмическое преобразование одного в другой.

В разделе 1.1 вывод типа шаблона пояснялся с использованием обобщенного шаблона функции

template<typename Т>

void f(ParamType param);

и обобщенного вызова

f(expr); // Вызов f с некоторым выражением

При вызове f компиляторы используют expr для вывода типов T и ParamType.

Когда переменная объявлена с использованием ключевого слова auto, оно играет роль Т в шаблоне, а спецификатор типа переменной действует как ParamType. Это проще показать, чем описать, так что рассмотрим следующий пример:

auto x = 27;

Здесь спецификатором типа для x является auto само по себе. С другой стороны, в объявлении

const auto cx = x;

спецификатором типа является const auto. А в объявлении