Каковы правила для выбора из перегруженных шаблонных функций?

"\n".charCodeAt(0);
10
задан CsTamas 24 July 2009 в 13:40
поделиться

4 ответа

Формально, когда сравнивая последовательности преобразования, преобразования lvalue игнорируются. Преобразования сгруппированы в несколько категорий, например корректировка квалификации ( T * -> T const * ), преобразование lvalue ( int [N] -> int * , void () -> void (*) () ) и другие.

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

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

Давайте сравним эти два параметра, посмотрев на их сигнатуру в их списке параметров функции.

void(T const&);
void(T*);

Если мы выберем какой-то уникальный тип Q для первого списка параметров и попытаемся сопоставить его со вторым списком параметров, мы получим сопоставление Q с T * . Это не удастся, поскольку Q не является указателем. Таким образом, второй по крайней мере так же специализирован, как и первый.

Если мы сделаем наоборот, мы сопоставим Q * с T const & . Ссылка удаляется, квалификаторы верхнего уровня игнорируются, а оставшийся T становится Q * . Это точное совпадение с целью частичного упорядочивания, и, таким образом, вывод преобразованного списка параметров второго кандидата по сравнению с первым завершается успешно. Поскольку другое направление (против второго) не увенчалось успехом, второй кандидат более специализирован, чем первый - и, как следствие, разрешение перегрузки предпочтет второе, если иначе возникнет двусмысленность.

На 13.3.3.2/3 : определено в 13.3.3.1.1, исключая любое преобразование Lvalue; последовательность преобразования идентичности считается подпоследовательностью любой последовательности преобразования, отличной от идентичности) или, если это не так [...]

Тогда 13.3.3 / 1

  • пусть ICSi (F) обозначает неявная последовательность преобразования, которая преобразует i-й аргумент в списке в тип i-го параметра жизнеспособной функции F. 13.3.3.1 определяет неявные последовательности преобразования, а 13.3.3.2 определяет, что означает, что одна последовательность неявного преобразования должна быть лучшая последовательность преобразования или худшая последовательность преобразования, чем другая.

С учетом этих определений жизнеспособная функция F1 определяется как лучшая функция, чем другая жизнеспособная функция F2, если для всех аргументов i ICSi (F1) не является худшей последовательностью преобразования чем ICSi (F2), и тогда [...]

  • F1 и F2 являются специализациями шаблонов функций, а шаблон функции для F1 более специализирован, чем шаблон для F2, в соответствии с правилами частичного упорядочивания, описанными в 14.5.5.2, или, если не так, [...]

Наконец, вот таблица неявных преобразований, которые может участвовать в стандартной последовательности преобразования по адресу 13.3.3.1.1 / 3 .

Последовательности преобразования http://img259.imageshack.us/img259/851/convs.png

6
ответ дан 4 December 2019 в 02:50
поделиться

На основе правил разрешения перегрузки (Приложение B к Шаблоны C ++: Полное руководство содержит хороший обзор) строковые литералы (const char []) ближе к T *, чем T &, потому что компилятор не делает различий между char [] и char *, поэтому T * является наиболее близким совпадением (const T * будет точным совпадением).

Фактически, если бы вы могли добавить:

template<typename T>
void foo(const T[] a)

(что вы не можете) , ваш компилятор скажет вам, что эта функция является переопределением:

template<typename T>
void foo(const T* a)
0
ответ дан 4 December 2019 в 02:50
поделиться

The full answer is quite technical.

First, string literals have char const[N] type.

Then there is an implicit conversion from char const[N] to char const*.

So both your template function match, one using reference binding, one using the implicit conversion. When they are alone, both your template functions are able to handle the calls, but when they are both present, we have to explain why the second foo (instantiated with T=char const[N]) is a better match than the first (instantiated with T=char). If you look at the overloading rules (as given by litb), the choice between

void foo(char const (&x)[4));

and

void foo(char const* x);

is ambigous (the rules are quite complicated but you can check by writing non template functions with such signatures and see that the compiler complains). In that case, the choice is made to the second one because that one is more specialized (again the rules for this partial ordering are complicated, but in this case it is because you can pass a char const[N] to a char const* but not a char const* to a char const[N] in the same way as void bar(char const*) is more specialized than void bar(char*) because you can pass a char* to a char const* but not vise-versa).

2
ответ дан 4 December 2019 в 02:50
поделиться

Причина "" - это символ *, который идеально подходит для функции foo (T *). Когда вы удалите это, компилятор попытается заставить его работать с foo (T &), что требует от вас передать ссылку на массив char, содержащий строку.

Компилятор не может сгенерировать одну функцию, которая будет получать ссылку на char, так как вы передаете весь массив, поэтому он должен разыменовать его.

-1
ответ дан 4 December 2019 в 02:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: