Когда auto используется против массива, почему он конвертируется в указатель, а не в ссылку? - PullRequest
18 голосов
/ 22 июня 2011

См. Приведенный ниже пример:

int arr[10];
int *p = arr; // 1st valid choice
int (&r)[10] = arr; // 2nd valid choice

Теперь, когда мы используем auto против arr, выбирается 1-й вариант.

auto x = arr; // x is equivalent to *p

Есть ли причина выбор указателя, а не ссылки для массива?

Ответы [ 4 ]

24 голосов
/ 22 июня 2011

Да. В этом выражении массив превращается в тип указателя из-за преобразования lvalue-to-rvalue.

Если вы хотите массив тип, а не указатель тип, то сделайте следующее:

auto & x = arr; //now it doesn't decay into pointer type!

& в целевом типе предотвращает переход массива в тип указателя!


x является массивом, а не указателем, может быть доказано как:

void f(int (&a)[10]) 
{
    std::cout << "f() is called. that means, x is an array!" << std::endl;
}
int main() {
     int arr[10];
     auto & x = arr; 
     f(x); //okay iff x is an int array of size 10, else compilation error!
}

Выход:

f() is called. that means, x is an array!

Демонстрация на ideone: http://www.ideone.com/L2Ifp

Обратите внимание, что f нельзя вызывать с типом указателя . Его можно вызвать с массивом int размером 10. Попытка вызвать его с помощью любого другого типа приведет к ошибке компиляции.

5 голосов
/ 22 июня 2011

Чтобы обеспечить стандартную ссылку на поведение, 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; не сможет скомпилироваться, а будет делать что-то полезное.

4 голосов
/ 22 июня 2011

auto производит значения.Это не будет производить ссылки.Имея это в виду, указатель является тривиальным преобразованием в значение, которое предлагает массив.

0 голосов
/ 22 июня 2011

Для массива arr само выражение arr означает &arr[0]. Это правило взято из C. Поэтому, IMO, автоматически выбирает указатель.

...