Ответ 1
В С++, как и в C, параметр, объявленный как тип массива, настраивается (во время компиляции) на тип указателя, в частности указатель на тип элемента массива.
Это происходит независимо от того, указан ли тип массива напрямую или через typedef (помните, что typedef не создает новый тип, просто псевдоним для существующего типа).
Итак, это:
typedef char ar[];
typedef char* pr;
void f2(ar x, pr y)
{
// ...
}
действительно означает:
void f2(char* x, char* y)
{
// ...
}
Другое правило, также разделяемое C и С++, заключается в том, что выражение типа массива в большинстве, но не во всех контекстах, неявно преобразуется в указатель на первый элемент объекта массива. Это означает, что если вы определяете объект массива:
char arr[10];
вы можете использовать имя этого объекта в качестве аргумента функции, которая принимает параметр char*
(который теряет информацию о границах).
В C случаи, когда это неявное преобразование не происходит, следующие:
- Когда выражение массива является операндом
sizeof
(sizeof arr
дает размер массива, а не размер указателя); - Когда выражение массива является операндом унарного
&
(&arr
является указателем на массив, а не указателем на указатель); и - Когда выражение массива является строковым литералом, используемым для инициализации объекта типа массива (
char s[] = "hello";
инициализируетs
как массив, а не как указатель).
Ни один из этих случаев (или другие случаи, которые происходят на С++) не отображаются в вашей программе, поэтому ваш вызов:
f2(data,ptr);
передает два значения указателя типа char*
в f2
.
Внутри f2
объекты параметров x
и y
являются типами char*
, поэтому std::is_same<decltype(x), decltype(y)>::value
является истинным.
Но типы ar
и pr
различны. ar
- это неполный тип массива char[]
, а pr
- тип указателя char*
.
Что объясняет вывод вашей программы. Странность возникает, потому что параметр x
, который вы определили с типом массива ar
, действительно имеет тип char*
, который является тем же самым типом, что и pr
.