Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 | страница 15
>const int cx = x; // cx имеет тип const int
>const int& rx = x; // rx является ссылкой на x как на const int
то выводимые типы для >param
и >Т
в различных выводах будут следующими:
>f(x); // Т - int, тип param - int&
>f(cx); // Т - const int, тип param - const int&
>f(rx); // Т - const int, тип param - const int&
Во втором и третьем вызовах обратите внимание, что, поскольку >cx
и >rx
объявлены как константные значения, >Т
выводится как >const int
тем самым приводя к типу параметра >const int&
. Это важно для вызывающего кода. Передавая константный объект параметру-ссылке, он ожидает, что объект останется неизменным, т.е. что параметр будет представлять собой ссылку на >const
. Вот почему передача константного объекта в шаблон, получающий параметр >T&
, безопасна: константность объекта становится частью выведенного для >Т
типа.
В третьем примере обратите внимание, что несмотря на то, что типом >rx
является ссылка, тип >T
выводится как не ссылочный. Вот почему при выводе типа игнорируется “ссылочность” >rx
.
Все эти примеры показывают ссылочные параметры, являющиеся lvalue, но вывод типа точно так же работает и для ссылочных параметров rvalue. Конечно, аргументы могут передаваться только ссылочным параметрам, являющимся rvalue, но это ограничение никак не влияет на вывод типов.
Если мы изменим тип параметра >f
с >Т&
на >const Т&
, произойдут небольшие изменения, но ничего удивительного не случится. Константность >cx
и >rx
продолжает соблюдаться, но поскольку теперь мы считаем, что >param
является ссылкой на >const
, >const
как часть выводимого типа >T
не требуется:
>template
>void f(const T& param); // param является ссылкой на const
>int x = 27; // Как и ранее
>const int cx = x; // Как и ранее
>const int& rx = x; // Как и ранее
>f(x); // Т - int, тип param - const int&
>f(cx); // Т - int, тип param - const int&
>f(rx); // Т - int, тип param - const int&
Как и ранее, “ссылочность” >rx
при выводе типа игнорируется.
Если бы >param
был указателем (или указателем на >const
), а не ссылкой, все бы работало, по сути, точно так же:
>template
>void f(T* param); // Теперь param является указателем
>int x = 27; // Как и ранее
>const int *px = &x; // px - указатель на x, как на const int
>f(&x); // Т - int, тип param - int*
>f(px); // Т - const int, тип param - const int*
Сейчас вы можете обнаружить, что давно усердно зеваете, потому что все это очень скучно, правила вывода типов в С++ работают так естественно для ссылок и указателей, что все просто очевидно! Это именно то, что вы хотите от системы вывода типов.