Правила привязки аргумента функции для передачи массива по ссылке против передаваемого указателя

Чтобы избежать путаницы, я очень хорошо понимаю разницу между массивами и указателями, концепцию распада к указателю и концепцию передачи массива с помощью ссылка в C ++ и т. д.

Мой вопрос здесь конкретно о правилах, используемых компилятором для выбора функции из набора функций перегрузка кандидатов, когда одна перегрузка принимает ссылку на массив, а другая перегрузка принимает указатель.

Например, предположим, что мы имеем:

template <class T, std::size_t N>
void foo(const T (&arr)[N])
{
std::cout << "Array-reference overload!" << std::endl;
}

template <class T>
void foo(const T* ptr)
{
std::cout << "Pointer overload!" << std::endl;
}

Если мы попытаемся вызвать шаблон функции foo() следующее:

const char arr[2] = "A";
foo(arr);

… тогда я ожидал бы, что первый Перегрузка, которая принимает ссылку на массив, будет выбрана компилятором.

Однако, используя GCC 4.9.2, если я скомпилирую приведенный выше код, я получаю сообщение об ошибке:

test.cpp:28:9: error: call of overloaded ‘foo(const char [2])’ is ambiguous

Мне неясно, почему обе перегрузки здесь считаются одинаково хорошими кандидатами компилятором, поскольку первая перегрузка точно соответствует типу, тогда как вторая перегрузка требует дополнительного шага затухания к указателю.

Теперь я могу заставить работать вышеупомянутую перегрузку, явно используя type_traits следующее:

template <class T, std::size_t N>
void foo(const T (&arr)[N])
{
std::cout << "Array-reference overload!" << std::endl;
}

template <class T>
void foo(T ptr, typename std::enable_if<std::is_pointer<T>::value>::type* = 0)
{
std::cout << "Pointer overload!" << std::endl;
}

В этом случае программа компилируется и выбирается перегрузка, которая принимает ссылку на массив. Однако я не понимаю, почему это решение должно быть необходимым. Я хотел бы понять, почему компилятор считает функцию, для которой указатель на затухание является равноправным вероятным кандидатом на перегрузку, в качестве ссылки на массив, когда передаваемый аргумент представляет собой массив.

7

Решение

первая перегрузка точно соответствует типу, тогда как вторая перегрузка требует дополнительного шага затухания до указателя.

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

Из стандарта, $ 16.3.3.1.1 Стандартные последовательности преобразования [over.ics.scs] Таблица 13 — Преобразования

Conversion                   Category               Rank         Subclause
No conversions required      Identity               Exact Match
... ...
Array-to-pointer conversion  Lvalue Transformation  Exact Match  [conv.array]
... ...

Стоит отметить, что ранг «Преобразование не требуется» (т.е. в случае 1-й перегрузки) также «Точное совпадение».

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]