Эффективный и современный С++. 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); // Шаблон с передачей параметра по ссылке