Чтобы обеспечить стандартную ссылку на поведение, 7.1.6.4 [dcl.spec.auto] параграф 6 гласит:
Как только тип идентификатора объявления определен в соответствии с 8.3, тип объявленной переменной с использованием идентификатора объявления определяется из типа ее инициализатора с использованием правил для вывода аргумента шаблона. Пусть T будет типом, который был определен для идентификатора переменной d. Получите P из T, заменив вхождения auto на ... новый шаблонный шаблон изобретенного типа U ... Тип, выведенный для переменной d, будет затем выведенным A, определенным с использованием правил вывода аргумента шаблона из вызова функции (14.8 .2.1), где P - тип параметра шаблона функции, а инициализатор для d - соответствующий аргумент. Если вычет не удался, декларация неверна.
Так что нам нужно искать в другом месте, в частности 14.8.2.1 [tmp.deduct.call] параграф 2:
Если P не является ссылочным типом: - Если A является типом массива, тип указателя, созданный стандартным преобразованием массива в указатель (4.2), используется вместо A для вывода типа
Для полноты, 4.2 [conv.array], пункт 1:
Значение l или значение типа «массив из N T» или «массив неизвестных границ T» может быть преобразовано в значение типа «указатель на T». Результатом является указатель на первый элемент массива.
Чтобы пройти через него, auto x = arr;
создает мнимую функцию template<typename P> f(P);
и пытается вывести P
из вызова f(arr)
. A
в этом случае - array of 10 int
, а P
не является ссылочным типом, поэтому A
становится вместо pointer to int
. Который просачивается вверх по цепочке до окончательного типа x
.
Так что, по сути, он рассматривается как указатель, потому что правила говорят, что он должен. Такое поведение просто более полезно, поскольку массивы нельзя назначать. В противном случае ваш auto x = arr;
не сможет скомпилироваться, а будет делать что-то полезное.