Se eles são relacionados
Por um momento, vamos supor que B
seja realmente uma base de D
. Então, para a chamada para check
, ambas as versões são viáveis porque Host
podem ser convertidas para D*
e B*
. É uma sequência de conversão definida pelo usuário, conforme descrito por 13.3.3.1.2
de 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 check
funçã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 *this
objeto não const (o argumento do objeto implícito ) por13.3.3.2/3b1sb4
e é usado para converter para B*
para a segunda check
funçã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 B
e D
!