Читать «Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14» онлайн - страница 12
Скотт Мейерс
Если вы готовы посмотреть сквозь пальцы на применение небольшого количества псевдокода, то можно рассматривать шаблон функции как имеющий следующий вид:
template<typename Т>
void(
Вызов может выглядеть следующим образом:
f(expr); // Вызов f с некоторым выражением
В процессе компиляции компилятор использует expr для вывода двух типов: типа Т
и типа ParamType
. Эти типы зачастую различны, поскольку ParamType
часто содержит “украшения”, например const
или квалификаторы ссылки. Например, если шаблон объявлен как
template<typename Т>
void f(const T& param); //
и мы осуществляем вызов
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(
f(
Случай 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
и Т
в различных выводах будут следующими: