Ответ 1
Как только мы получим наши функции-кандидаты (оба bar
s), а затем сведем их к жизнеспособным функциям (все еще обе bar
s), мы должны определить наилучшую жизнеспособную функцию. Если их больше одного, мы получаем ошибку двусмысленности. Шаги, которые мы предпринимаем для определения наилучшего, изложены в [over.match.best]:
[A] жизнеспособная функция F1 определена как лучшая функция, чем другая жизнеспособная функция F2, если для всех аргументов i, ICS i (F1) не является худшей последовательностью преобразования, чем ICS i (F2), а затем - для некоторого аргумента j ICS j (F1) является лучшей последовательностью преобразования, чем ICS j (F2), или, если не это,
Обе функции принимают аргумент типа int
, поэтому обе последовательности преобразования идентичны. Мы продолжаем.
- контекст является инициализацией по пользовательскому преобразованию [...]
Не применяется.
- контекст представляет собой инициализацию функцией преобразования для привязки прямого ссылки (13.3.1.6) ссылки на тип функции, [...]
Не применяется.
- F1 не является специализированной функцией шаблона, а F2 является специализированной функцией шаблона или, если не это,
Оба bar<int>
являются специализированными шаблонами функций. Поэтому мы переходим к самой последней точке маркера, чтобы определить лучшую жизнеспособную функцию.
- F1 и F2 - специализированные шаблоны функций, а шаблон функции для F1 - более специализированный чем шаблон для F2 в соответствии с правилами частичного упорядочения, описанными в 14.5.6.2.
Частичные правила упорядочения в основном сводятся к тому, что мы синтезируем новые уникальные типы для аргументов как перегрузок bar
, так и вычитания шаблонов при другой перегрузке.
Сначала рассмотрим перегрузку "b". Синтезируйте тип typename identity<Unique1>::type
и попытайтесь выполнить вычитание шаблона против T
. Это удается. Простейший листинг шаблона вывода есть.
Затем рассмотрим "a" перегрузку. Синтезируйте тип Unique2
и попытайтесь выполнить вывод шаблона против typename identity<T>::type
. Это не удается! Это не выведенный контекст - вычет не может быть успешным.
Так как вычет типа шаблона преуспевает только в одном направлении, перегрузка bar(typename identity<T>::type)
считается более специализированной и выбирается как лучший жизнеспособный кандидат.
bogdan представляет еще один интересный случай для рассмотрения частичного заказа. Вместо этого сравните:
template <typename T> void bar(T, T); // "c"
template <typename T> void bar(T, typename identity<T>::type ); // "d"
bar(5,5);
bar<int>(5, 5);
Опять же, оба кандидата жизнеспособны (на этот раз даже без явного указания T
), поэтому мы рассмотрим правило частичного упорядочения.
Для "c" перегрузки мы синтезируем аргументы типа UniqueC, UniqueC
и пытаемся выполнить вычет против T, typename identity<T>::type
. Это выполняется успешно (с T == UniqueC
). Таким образом, "c" по крайней мере так же специализирован, как "d" .
Для "d" перегрузки мы синтезируем аргументы типа UniqueD, typename identity<UniqueD>::type
и пытаемся выполнить вывод на T, T
. Это не удается! Аргументы имеют разные типы! Таким образом, "d" не является, по меньшей мере, таким же специализированным, как "c".
Таким образом, вызывается перегрузка "c".