Ответ 1
Разрешение перегрузки пытается найти наилучшую функцию следующим образом:
(1) [over.match.best]/1:
Учитывая эти определения, жизнеспособная функция
F1
определяется как лучше, чем другая жизнеспособная функцияF2
, если для всех аргументов i,ICSi(F1)
не является худшей последовательностью преобразования, чемICSi(F2)
, а затем - для некоторого аргумента j,ICSj(F1)
является лучшим преобразованием чемICSj(F2)
, или, если это не так, - контекст - это инициализация путем пользовательского преобразования (см. 8.5, 13.3.1.5 и 13.3.1.6) и стандартную последовательность преобразования из возвращаемого типаF1
в тип назначения (то есть тип объекта, являющегося инициализировано) является лучшей последовательностью преобразования, чем стандартная последовательность преобразования из возвращаемого типаF2
в пункт назначения тип.
[Пример:struct A { A(); operator int(); operator double(); } a; int i = a; // a.operator int() followed by no conversion is better // than `a.operator double()` // followed by a conversion to `int` float x = a; // ambiguous: both possibilities require conversions, // and neither is better than the other
- конец примера] или, если не тот,
- F1 - не шаблон функция, а F2 - специализированная функция шаблона, или, если не что, - F1 и F2 - специализированные шаблоны функций, а шаблон функции для F1 более специализирован, чем шаблон для F2 в соответствии с правилами частичного упорядочения, описанными в 14.5.6.2.
Случай 1:
но не тот, который принимает
T&
более специализированный, чемT
?
В соответствии с разрешением перегрузки преобразование не лучше (оба являются конверсиями идентичности, которые являются точными совпадениями), и поскольку никакая другая марка в (1) не применяется, выполняется частичное упорядочение. [temp.deduct.partial]/5 говорит, что ссылки заменяются типом, на который они ссылаются для частичного упорядочения:
Прежде чем сделать частичное упорядочение, некоторые преобразования выполняется для типов, используемых для частичного упорядочения:
- ЕслиP
является ссылочный тип,P
заменяется типом, на который ссылается.
- ЕслиA
является ссылочный тип,A
заменяется типом, обозначенным.
Поскольку параметры шаблонов параметров полностью идентичны, нетрудно видеть, что вычеты друг против друга успешны в обоих направлениях - поэтому ни один шаблон не является более специализированным, чем другой.
Случай 2:
Частичное упорядочение здесь не требуется. Определенное пользователем преобразование из X<int>
в X<int&>
имеет худший ранг, чем преобразование X<int>
в X<int>
. Последнему присваивается ранг Точного соответствия по [over.ics.user]/4:
Преобразование выражения типа класса в один и тот же тип класса заданный ранг Точного соответствия, [...]
Таким образом, это, очевидно, лучшее преобразование, чем X<int>
to X<int&>
, которое имеет ранг конверсии. То же самое идет наоборот, для X<int&>
до X<int>
.
Случай 3:
Третий случай похож на первый. X<int>
и X<int&>
оба имеют шаблон конструктора, который может принимать произвольную специализацию F
. (1) говорит нам, что, поскольку ни одна из последовательностей преобразования не лучше других (фактически, они полностью идентичны), выбирается более специализированный шаблон.
template <class T> void bar(X<T>); // #1
template <class T> void bar(X<T&>); // #2
// Call:
bar<int>( F<int>() );
Возвращаясь к [temp.deduct.partial], выполняется вывод типа. Уникальный тип, называемый Unique
, синтезируется для параметра шаблона каждого шаблона аргумента. Выполняются следующие процедуры с соответствующими результатами - обратите внимание, что при вызове с помощью F<int>
шаги выполняются точно так же, как и при использовании F<int&>
(и любой другой специализации F
):
- шаблон # 1 как шаблон шаблона и шаблон # 2 в качестве шаблона аргумента,
X<Unique&>
выводится наX<T>
, что даетT=Unique&
. С другой стороны, - шаблон # 2 в качестве шаблона параметра для шаблона # 1 в качестве шаблона аргумента,
X<Unique>
выводится наX<T&>
, , что приводит к ошибке дедукции.
Как мы видим, шаблон №2 более специализирован. При использовании в качестве шаблона аргумента на шаге 1 дедукция преуспела, тогда как для шаблона № 1 в качестве шаблона аргумента на шаге 2 вывод не удался. Поэтому вызывается вторая специализированная специализированная функция шаблонов.