Если они связаны
Давайте на мгновение предположим, что B
на самом деле это база D
. Тогда для вызова check
обе версии жизнеспособны, потому что Host
могут быть преобразованы в D*
и B*
. Это определяется пользователем последовательность преобразования , как описано 13.3.3.1.2
от Host<B, D>
к D*
и B*
соответственно. Для поиска функций преобразования, которые могут преобразовать класс, следующие функции-кандидаты синтезируются для первой check
функции в соответствии с13.3.1.5/1
D* (Host<B, D>&)
Первая функция преобразования не является кандидатом, потому что B*
не может быть преобразована вD*
.
Для второй функции существуют следующие кандидаты:
B* (Host<B, D> const&)
D* (Host<B, D>&)
Это два кандидата в функции преобразования, которые принимают ведущий объект. Первый принимает его по константной ссылке, а второй - нет. Таким образом, второй лучше подходит для неконстантного *this
объекта ( подразумеваемого аргумента объекта ) 13.3.3.2/3b1sb4
и используется для преобразования в B*
для второгоcheck
функции.
Если вы удалите константу, у нас будут следующие кандидаты
B* (Host<B, D>&)
D* (Host<B, D>&)
Это означало бы, что мы больше не можем выбирать по константе. В обычном сценарии разрешения перегрузки вызов теперь будет неоднозначным, поскольку обычно возвращаемый тип не участвует в разрешении перегрузки. Однако для функций преобразования есть лазейка. Если две функции преобразования одинаково хороши, то их возвращаемый тип решает, кто из них лучше 13.3.3/1
. Таким образом, если вы удалите константу, тогда будет взята первая, потому что B*
лучше преобразуется в, B*
чем D*
вB*
.
Какая последовательность преобразования, определяемая пользователем, лучше? Один для второй или первой функции проверки? Правило состоит в том, что определенные пользователем последовательности преобразования можно сравнивать, только если они используют одну и ту же функцию преобразования или конструктор в соответствии с 13.3.3.2/3b2
. Здесь именно так: оба используют вторую функцию преобразования. Обратите внимание, что таким образом const важна, потому что она заставляет компилятор выполнять вторую функцию преобразования.
Раз уж мы можем их сравнивать - какой из них лучше? Правило состоит в том, что лучшее преобразование из возвращаемого типа функции преобразования в целевой тип выигрывает (опять же 13.3.3.2/3b2
). В этом случае D*
лучше преобразуется в, D*
чем вB*
. Таким образом выбирается первая функция и мы распознаем наследование!
Обратите внимание, что, поскольку нам никогда не нужно было фактически преобразовывать в базовый класс, мы можем таким образом распознать частное наследование, потому что возможность преобразования из a D*
в a B*
не зависит от формы наследования в соответствии с4.10/3
Если они не связаны
Теперь предположим, что они не связаны по наследству. Таким образом, для первой функции у нас есть следующие кандидаты
D* (Host<B, D>&)
И на секунду у нас теперь есть еще один набор
B* (Host<B, D> const&)
Поскольку мы не можем D*
выполнить преобразование в, B*
если у нас нет отношения наследования, у нас теперь нет общей функции преобразования для двух пользовательских последовательностей преобразования! Таким образом, мы были бы двусмысленными, если бы не тот факт, что первая функция является шаблоном. Шаблоны - это второй вариант, когда есть функция, не являющаяся шаблоном, которая, согласно 13.3.3/1
. Таким образом, мы выбираем нешаблонную функцию (вторую) и понимаем, что нет наследования между B
и D
!