Я думаю, что ключевой частью связанного решения было то, что независимо от того, каким будет конечный результат (связанный или не связанный) - выбранная последовательность преобразования фактически не будет включать наследуемость, для которой проверяется. Компилятор учитывает это в процессе выбора соответствующей версии функции check
. Однако каждый раз в конце выбранный путь фактически не будет его использовать.
Однако в вашем коде, если классы связаны, вызов check
действительно использует наследование, преобразованное из Child*
в B*
. И это - я боюсь, это не может быть легко исправлено, поскольку подход, который вы представили, сильно отличается.
Если связано
Ваше решение
Child
равно D
, следовательно, также B
. Поэтому существует преобразование из Child*
в B*
. Поэтому первая версия Check
жизнеспособна. Вторая версия Check
является жизнеспособной, так как Child
также dummy<int>
и, следовательно, Child*
- dummy<int>*
. Первая версия выбрана, поскольку она не требует специализации параметров шаблона.
Связанное решение
Для первой версии check
: Host<B, D>
преобразуется через преобразование, определенное пользователем, в D*
. Тип результата преобразования в точности соответствует аргументу функции. Наследование здесь не используется.
Для второй версии check
: Host<B, D>
снова преобразуется через пользовательское преобразование в D*
. Тип результата преобразования - D*
, который может быть далее преобразован в B*
для соответствия аргументу функции. Наследование здесь действительно используется.
Однако в конце компилятор выбирает первую версию, поскольку было отмечено, что результат преобразования лучше соответствует аргументу check
.
Если не связано
Ваше решение
Child
не B
, поэтому первая версия Check
не является опцией. Вторая версия жизнеспособна, так как Child
по-прежнему dummy<int>
, поэтому может быть специализированным с dummy<T>
. Поскольку есть только один вариант, выбор тривиален.
Связанное решение
Для первой версии check
: Host<B, D>
преобразуется в D*
путем преобразования, определенного пользователем.
Для второй версии check
: Host<B, D>
преобразуется в const Host<B, D>
, а затем в B*
путем преобразования, определенного пользователем.
Пути были бы несопоставимы, если бы не тот факт, что только одна версия функции check
имеет аргументы шаблона.
Как видите, два подхода значительно различаются.