[Из песочницы] 1. По мотивам Мейерса «Эффективный и современный c++» — вывод типа шаблона

habr.png

Добрый день, дорогой читатель!

Эта статья — первая в цикле статей-конспектов, которые я буду писать по ходу прочтения книги Скотта Мейерса «Эффективный и современный c++». Каждой из таких статей будет соответствовать отдельная директория в специально заведенном на github.com проекте с примерами использования описываемых возможностей и приемов.

Удачное проектирование — это когда потребитель не знает как работает устройство, но его всё устраивает.

Вывод типа шаблона — это когда есть шаблонная функция, к примеру, а вызов её осуществляется без всяких таким template и угловых скобочек. Компилятор при этом угадывает какой тип надо будет использовать в конкретном объекте функции.

Мейерс разделяет тип — «T», который выводится и вид — «ParamType», который прописывается программистом в определении параметра.


1. Тип аргумента — ссылка или указатель

Для того чтобы было быстро понять правило выведения я буду отражать его в виде шаблона:

входной тип —> тип, параметр —> выведенный тип [, конечный-тип параметра]


Пример со ссылкой:

template // выведенный тип T
void func(T& param) // тип параметра - T&

int x = 0; // входной тип int 
func(x);

При выводе типа T ссылочность (*, &) отбрасывается, потому что она уже указана при определении функции, как-бы подразумевается «вы там передавайте что угодно, мы будем считать, что это не ссылка, потому что ссылочность уже добавлена в месте потребления — в нашей функции f»

По такому же принципу отбрасывается константность, если она указана в параметре функции. На ссылки, указатели константность как бы накладывается исключающая маска.


Схема выведения

// отбрасывается ссылочность
int —> (T & param) —> int;
const int —> (T & param) —> const int;
const int & —> (T & param)  —> const int

// отбрасывается константность
int —> (const T & param) —> int;
const int —> (const T & param) —> int;
const int & —> (const T & param) —> int;

// отбрасывается ссылочность  
int * —> (T * param) —> int;
const int —> (T * param) —> const int;
const int * —> (T * param)  —> const int;

// отбрасывается константность
int * —> (const T * param) —> int;
const int —> (const T * param) —> int;
const int * —> (const T * param)  —> int;


2. Тип аргумента — универсальная ссылка

Скот оговаривается, что универсальные ссылки будут рассматриваться позже, поэтому правила для параметров, которые здесь он делит на rvalue и lvalue нужно просто запомнить особо не вдумываясь.

template
void func(const T&& param)


Правила вывода для lvalue

ВНИМАНИЕ — это единственный случай когда T выводится как ссылка вот этот, когда в описании функции универсальная ссылка lvalue

lvalue int —> (T &¶m) —> int &, param - int&
lvalue const int —> (T &¶m) —> const int &, param - const int&
lvalue const int & —> (T &¶m) —> const int &, param - const int&

Тип самого параметра тоже подменяется ибо негоже lvalue использовать как универсальную ссылку, а то ведь её так можно будет move, только тсс, это секрет ;)

К слову если мы попытаемся написать что-то типа T myVar, то обязательно получим вот такое «declared as reference but not initialized» — ссылка же:)


Правила вывода для rvalue — применяются правила из

rvalue int —> (T &¶m) —> int, param - int&&

Уже сейчас видно, что универсальные ссылки «включаются» только для rvalue-временных объектов, в других случаях, когда аргумент не является универсальной ссылкой, различие rvalue, lvalue не делается


3. Передача по значению (как есть)

При передаче по значению константность и ссылочность исходного аргумента отбрасывается за ненадобностью ведь это абсолютно новые самостоятельные объекты, зачем им квалификаторы того, с чем они не связаны?

int —> (T param) —> int
const int —> (T param) —> int
const int & —> (T param) —> int
// Хитрый пример с отбрасыванием крайней константности указателя, который копируется при передаче
const char * const —> (T param) —>  const char *


Предположу, что другие безумные и нелогичные сочетания вызовут ошибки компиляции, почти всегда, оказывается, работа компилятора объяснима, надо только эти объяснения один раз выслушать.

© Habrahabr.ru