Ответ 1
Отказ от ответственности: типы, которые мы рассматриваем, всегда являются типами параметров. Типы/значения/etc. фактических переданных аргументов рассматриваются исключительно при разрешении перегрузки, никогда в частичном порядке.
Частичное упорядочение рассматривает обе перегрузки в двух "поворотах", в которых один шаблон всегда является шаблоном параметра , а другой шаблон - шаблон аргумента. [Temp.deduct.partial]/2:
Для каждого из задействованных шаблонов существует оригинальный тип функции и преобразованный тип функции. [..] Вычет процесс использует преобразованный тип в качестве шаблона аргумента и исходный тип другого шаблона в качестве шаблона параметра. Эта процесс выполняется дважды для каждого типа, участвующего в частичном упорядочении сравнение: один раз используя преобразованный шаблон-1 в качестве аргумента шаблона и шаблона-2 в качестве шаблона параметра и снова используя преобразованный шаблон-2 в качестве шаблона аргумента и шаблона-1 в качестве шаблон параметра.
Вы должны быть знакомы с тем, как преобразуются "шаблоны". Это указано в п. 14.5.6.2/3.
Чтобы создать преобразованный шаблон, для каждого типа, не-типа или параметр шаблона шаблона (включая пакеты параметров шаблона (14.5.3)) синтезируют уникальный шаблон типа, значения или класса соответственно и подставлять его для каждого вхождения этого параметра в типе функции шаблона.
Итак, наши (преобразованные) шаблоны аргументов
void foo( Unique1& );
void foo( Unique2 const& );
[temp.deduct.partial]/3 и /4:
Типы, используемые для определения порядка, зависят от контекста в которые выполняются в частичном порядке:
- В контексте вызов функции, используемые типы являются теми параметрами параметров функции для который вызов функции имеет аргументы. [..]
Каждый тип, назначенный выше из шаблона параметра и соответствующего типа из аргумента шаблон используются как типы
P
иA
.
Таким образом, мы имеем два оборота, и в обоих случаях мы имеем тип P
и тип A
:
Поворот 1:
P1
: T const&
A1
: Unique1&
Поворот 2:
P2
: T&
A2
: Unique2 const&
Но перед началом забавы некоторые преобразования также выполняются на этих типах - я сокращен [temp.deduct.partial]/5 и /7:
- Если
P
илиA
являются ссылками, то они заменяются типом, на который они ссылаются. - Удаляются все CV-квалификаторы верхнего уровня.
Обратите внимание, что удаленные cv-квалификаторы "запоминаются" позже. [temp.deduct.partial]/6:
Если оба
P
иA
были ссылочными типами (перед заменой на тип, упомянутый выше), определить, какой из двух типов (если таковой имеется) более квалифицированный, чем другой; в противном случае типы рассматриваются быть одинаково квалифицированным для частичного заказа. Результат этого определения будет использоваться ниже.
Таким образом, мы остаемся с
Поворот 1:
P1
: T
A1
: Unique1
Поворот 2:
P2
: T
A2
: Unique2
Теперь мы выполняем вывод - который явно преуспевает в обоих поворотах, устанавливая T=Unique[1/2]
. Из [temp.deduct.partial]/8:
Если вывод для успешного типа задан, тип из шаблона аргумента считается быть как минимум таким же специализированным, как тип из шаблона параметра.
Это дает нам то, что Unique1&
по крайней мере так же специализировано, как T const&
, и что Unique2 const&
по крайней мере так же специализирован, как T&
.
Однако здесь [temp.deduct.partial]/(9.2) выполняется:
Если для данного типа вывод преуспевает в обоих направлениях (т.е. типы идентичны после преобразований выше) и как
P
, так иA
были ссылочными типами (перед заменой указанным типом выше):
[..]; в противном случае
, если тип из шаблона аргумента более cv-квалифицирован, чем тип из шаблона параметра (как описано выше), тип параметра не считается по меньшей мере таким же специализированным, как аргумент тип.
Вступают в игру запоминающиеся cv-квалификаторы. A2
является "более cv-квалификацией (как описано выше)", чем P2
, поэтому P2
не считается, по меньшей мере, таким же специализированным, как A2
.
Наконец, [temp.deduct.partial]/10:
Шаблон функции
F
по меньшей мере такой же специализированный, как шаблон функцииG
если для каждой пары типов, используемых для определения порядка, тип изF
по крайней мере так же специализирован, как тип изG
.F
является более специализированным чемG
, еслиF
не менее специализирован какG
иG
не является, по меньшей мере, таким же специализированным, какF
.
означает, что, поскольку тип T&
не является, по крайней мере, специализированным как Unique2 const&
, и мы уже установили, что T const&
не менее специализирован как Unique1&
, T const&
-overload более специализирован, чем T&
-overload.
Вышеупомянутое правило в пункте 9 в настоящее время является предметом CWG # 2088, созданного четыре месяца назад Р. Смитом:
Поздние тай-брейки для ссылок lvalue-vs-rvalue и cv-квалификация в пункте 14.8.2.4 [temp.deduct.partial] 9 приложенное
Если для данного типа вывод преуспевает в обоих направлениях (т.е. типы идентичны после преобразований выше) и оба
P
иA
были ссылочными типами (до замены на тип, упомянутый выше):Однако это основано на ложном предположении. [...] Нам нужно решить, является ли правило "удержание успешным в обоих направлениях" или "типы идентичны". Последнее кажется более разумным.
Это не изменит результат, установленный, поскольку типы, которые мы получили, действительно идентичны.