Se eles são relacionados
Por um momento, vamos supor que Bseja realmente uma base de D. Então, para a chamada para check, ambas as versões são viáveis porque Hostpodem ser convertidas para D* e B* . É uma sequência de conversão definida pelo usuário, conforme descrito por 13.3.3.1.2de Host<B, D>para D*e B*respectivamente. Para encontrar funções de conversão que podem converter a classe, as seguintes funções candidatas são sintetizadas para a primeira checkfunção de acordo com13.3.1.5/1
D* (Host<B, D>&)
A primeira função de conversão não é candidata, porque B*não pode ser convertida para D*.
Para a segunda função, existem os seguintes candidatos:
B* (Host<B, D> const&)
D* (Host<B, D>&)
Esses são os dois candidatos à função de conversão que usam o objeto host. O primeiro o considera por referência const e o segundo não. Assim, o segundo é uma combinação melhor para o *thisobjeto não const (o argumento do objeto implícito ) por13.3.3.2/3b1sb4 e é usado para converter para B*para a segunda checkfunção.
Se você remover o const, teríamos os seguintes candidatos
B* (Host<B, D>&)
D* (Host<B, D>&)
Isso significaria que não podemos mais selecionar por constância. Em um cenário de resolução de sobrecarga comum, a chamada agora seria ambígua porque normalmente o tipo de retorno não participará da resolução de sobrecarga. Para funções de conversão, no entanto, existe uma porta dos fundos. Se duas funções de conversão forem igualmente boas, o tipo de retorno delas decidirá quem é a melhor de acordo com 13.3.3/1. Portanto, se você remover o const, o primeiro será usado, porque B*converte melhor em do B*que D*em B*.
Agora, qual sequência de conversão definida pelo usuário é melhor? Aquele para a segunda ou a primeira função de verificação? A regra é que as sequências de conversão definidas pelo usuário só podem ser comparadas se usarem a mesma função de conversão ou construtor de acordo com 13.3.3.2/3b2. Este é exatamente o caso aqui: Ambos usam a segunda função de conversão. Observe que, portanto, const é importante porque força o compilador a assumir a segunda função de conversão.
Já que podemos compará-los - qual é o melhor? A regra é que a melhor conversão do tipo de retorno da função de conversão para o tipo de destino vence (novamente por 13.3.3.2/3b2). Nesse caso, D*converte melhor em do D*que em B*. Assim, a primeira função é selecionada e reconhecemos a herança!
Observe que, uma vez que nunca precisamos realmente converter para uma classe base, podemos reconhecer a herança privada porque se podemos converter de umD* para a B*não depende da forma de herança de acordo com4.10/3
Se eles não são relacionados
Agora vamos assumir que eles não estão relacionados por herança. Assim, para a primeira função, temos os seguintes candidatos
D* (Host<B, D>&)
E para o segundo, agora temos outro conjunto
B* (Host<B, D> const&)
Visto que não podemos converter D*para B*se não tivermos uma relação de herança, agora não temos nenhuma função de conversão comum entre as duas sequências de conversão definidas pelo usuário! Assim, seríamos ambíguos se não fosse o fato de que a primeira função é um modelo. Os modelos são a segunda escolha quando há uma função não-modelo que é igualmente boa de acordo com 13.3.3/1. Assim, selecionamos a função não modelo (a segunda) e reconhecemos que não há herança entre Be D!