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



, в процессе вывода типа сохраняется, но константность самого >ptr игнорируется при создании нового указателя >param.

Аргументы-массивы

Мы рассмотрели большую часть материала, посвященного выводу типов шаблонов, но есть еще один угол, в который стоит заглянуть. Это отличие типов массивов от типов указателей, несмотря на то что зачастую они выглядят взаимозаменяемыми. Основной вклад в эту иллюзию вносит то, что во множестве контекстов массив преобразуется в указатель на его первый элемент. Это преобразование позволяет компилироваться коду наподобие следующего:

>const char name[] = "Briggs";  // Тип name - const char[13]

>const char * ptrToName = name; // Массив становится указателем

Здесь указатель >ptrToName типа >const char* инициализируется переменной name, которая имеет тип >const char[13].Эти типы (>const char* и >const char[13]) не являются одним и тем же типом, но благодаря правилу преобразования массива в указатель приведенный выше код компилируется.

Но что будет, если передать массив шаблону, принимающему параметр по значению?

>template

>void f(T param); // Шаблон, получающий параметр по значению


>f(name);         // Какой тип Т и param будет выведен?

Начнем с наблюдения, что не существует такой вещи, как параметр функции, являющийся массивом. Да, да — приведенный далее синтаксис корректен:

>void myFunc(int param[]);

Однако объявление массива рассматривается как объявление указателя, а это означает, что функция myFunc может быть эквивалентно объявлена как

>void myFunc(int* param); // Та же функция, что и ранее

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

Поскольку объявление параметра-массива рассматривается так, как если бы это было объявление параметра-указателя, тип массива, передаваемого в шаблонную функцию по значению, выводится как тип указателя. Это означает, что в вызове шаблонной функции >f ее параметр типа выводится как >const char*:

>f(name); // nаmе - массив, но Т - const char*

А вот теперь начинаются настоящие хитрости. Хотя функции не могут объявлять параметры как истинные массивы, они могут объявлять параметры, являющиеся ссылками на массивы! Так что если мы изменим шаблон >f так, чтобы он получал свой аргумент по ссылке,

>template

>void f(T& param); // Шаблон с передачей параметра по ссылке