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

Скотт Мейерс

Если вы готовы посмотреть сквозь пальцы на применение небольшого количества псевдокода, то можно рассматривать шаблон функции как имеющий следующий вид:

template<typename Т>

void(ParamType param);

Вызов может выглядеть следующим образом:

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

В процессе компиляции компилятор использует expr для вывода двух типов: типа Т и типа ParamType. Эти типы зачастую различны, поскольку ParamType часто содержит “украшения”, например const или квалификаторы ссылки. Например, если шаблон объявлен как

template<typename Т>

void f(const T& param); // ParamType - const T&

и мы осуществляем вызов

int x = 0;

f(x); // Вызов f с параметром int

то Т выводится как int, а ParamType — как const int&.

Вполне естественно ожидать, что тип, выведенный для Т, тот же, что и тип переданного функции аргумента, т.е. что Т — это тип выражения expr. В приведенном выше примере это так: x — значение типа int и Т выводится как int. Но вывод не всегда работает таким образом. Тип, выведенный для T, зависит не только от типа expr, но и от вида ParamType. Существует три случая.

• ParamType представляет собой указатель или ссылку, но не универсальную ссылку. (Универсальные ссылки рассматриваются в разделе 5.2. Пока что все, что вам надо знать, — что они существуют и не являются ни ссылками lvalue, ни ссылками rvalue.)

• ParamType является универсальной ссылкой.

• ParamType не является ни указателем, ни ссылкой.

Следовательно, нам надо рассмотреть три сценария вывода. Каждый из них основан на нашем общем виде шаблонов и их вызова:

template<typename Т>

void f(ParamType param);

f(expr); // Вывод Т и ParamType из expr

Случай 1. ParamType является указателем или ссылкой, но не универсальной ссылкой

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

1. Если типом expr является ссылка, ссылочная часть игнорируется.

2. Затем выполняется сопоставление типа expr с ParamType для определения Т. Например, если у нас имеются шаблон

template<typename Т>

void f(T& param); // param представляет собой ссылку

и объявления переменных

int x = 27;        // x имеет тип int

const int cx = x;  // cx имеет тип const int

const int& rx = x; // rx является ссылкой на x как на const int

то выводимые типы для param и Т в различных выводах будут следующими: