Ответ 1
Вы думаете: если мой параметр не будет постоянным (или если аргумент будет постоянным), то указатель будет идеальным совпадением. Это верно. Разница в том, что у меня есть, это const
. Поэтому просто добавив const
к вышеприведенному сценарию, я также должен получить перегрузку указателя. Это тоже правильно. Теперь, как это может быть, так как вы явно получаете эталонную перегрузку? Ну, код не соответствует вашей мысли. Вот код, который будет соответствовать вашей линии мышления, и это действительно выбрало бы перегрузку указателя:
template <class T> void Foo(T* const x);
template <class T> void Foo(T const &x);
Обратите особое внимание на место const
. Я добавил const
как квалификатор верхнего уровня. Пока T const &x
эквивалентен тому, что у вас есть const T& x
, T* const x
не совпадает с const T* x
.
Позволяет увидеть разрешение перегрузки в этом случае:
fun | T | parameter | argument
-----------------------------------------+------+--------------+-----------
template <class T> void Foo(T* const x) | int | int* const | int*
template <class T> void Foo(T const &x) | int* | int* const & | int*
Позволяет увидеть перегрузку с вашей версией:
fun | T | parameter | argument
-----------------------------------------+------+--------------+-----------
template <class T> void Foo(const T* x) | int | const int* | int*
template <class T> void Foo(T const &x) | int* | int* const & | int*
Как вы можете видеть в первой версии, просто добавление верхнего уровня const предпочтительнее и выбрана перегрузка указателя. Для преобразования указателя не требуется.
Во втором случае для перегрузки указателя требуется преобразование указателя от pointer to mutable
до pointer to const
. Это разные типы указателей. Но со второй перегрузкой не требуется преобразования указателя. Просто добавьте верхний уровень const
.
Это в лучшем случае лучшее, что я могу объяснить, не переходя к тому, что говорится в разделе стандарта x.y.z