Если они связаны
Давайте на минутку предположим, что 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
функции.
Если бы вы удалили const, у нас были бы следующие кандидаты
B* (Host<B, D>&)
D* (Host<B, D>&)
Это будет означать, что мы больше не можем выбирать по постоянству. В обычном сценарии разрешения перегрузки вызов теперь будет неоднозначным, поскольку обычно возвращаемый тип не участвует в разрешении перегрузки. Для функций преобразования, однако, есть черный ход. Если две функции преобразования одинаково хороши, то тип возвращаемого значения определяет, кто лучше, согласно 13.3.3/1
. Таким образом, если вы удалите const, то будет взято первое, потому что B*
лучше преобразуется в B*
, чем D*
в B*
.
Какая определенная пользователем последовательность преобразования лучше? Один для второй или первой функции проверки? Правило состоит в том, что определенные пользователем последовательности преобразования могут сравниваться, только если они используют одну и ту же функцию преобразования или конструктор в соответствии с 13.3.3.2/3b2
. Это как раз тот случай: оба используют вторую функцию преобразования. Обратите внимание, что, таким образом, const важен, потому что он заставляет компилятор взять вторую функцию преобразования.
Так как мы можем сравнить их - какой из них лучше? Правило заключается в том, что выигрывает лучшее преобразование из возвращаемого типа функции преобразования в тип назначения (снова на 13.3.3.2/3b2
). В этом случае D*
конвертируется лучше в D*
, чем в B*
. Таким образом, выбирается первая функция, и мы распознаем наследование!
Обратите внимание, что, поскольку нам никогда не требовалось на самом деле преобразовать в базовый класс, мы можем таким образом распознать личное наследование , потому что мы можем преобразовать из D*
в B*
не зависит от формы наследования согласно 4.10/3
Если они не связаны
Теперь давайте предположим, что они не связаны наследством. Таким образом, для первой функции у нас есть следующие кандидаты
D* (Host<B, D>&)
А для второго у нас теперь есть другой набор
B* (Host<B, D> const&)
Поскольку мы не можем преобразовать D*
в B*
, если у нас нет отношения наследования, у нас теперь нет общей функции преобразования среди двух пользовательских последовательностей преобразования! Таким образом, мы были бы неоднозначными , если бы не тот факт, что первая функция является шаблоном. Шаблоны - второй выбор, когда есть не шаблонная функция, которая одинаково хороша в соответствии с 13.3.3/1
. Таким образом, мы выбираем не шаблонную функцию (вторую) и признаем, что между B
и D
!
нет наследования