Se sono correlati
Supponiamo per un momento che B
sia effettivamente una base di D
. Quindi per la chiamata a check
, entrambe le versioni sono valide perché Host
possono essere convertite in D*
e B*
. È una sequenza di conversione definita dall'utente come descritta rispettivamente da 13.3.3.1.2
da Host<B, D>
a D*
e B*
. Per trovare funzioni di conversione che possono convertire la classe, le seguenti funzioni candidate vengono sintetizzate per la prima check
funzione secondo13.3.1.5/1
D* (Host<B, D>&)
La prima funzione di conversione non è una candidata, perché B*
non può essere convertita in D*
.
Per la seconda funzione esistono i seguenti candidati:
B* (Host<B, D> const&)
D* (Host<B, D>&)
Questi sono i due candidati alla funzione di conversione che accettano l'oggetto host. Il primo lo prende per riferimento const, e il secondo no. Quindi il secondo è una corrispondenza migliore per l' *this
oggetto non const (l' argomento dell'oggetto implicito ) da 13.3.3.2/3b1sb4
e viene utilizzato per la conversione B*
per la seconda check
funzione.
Se rimuovessi const, avremmo i seguenti candidati
B* (Host<B, D>&)
D* (Host<B, D>&)
Ciò significherebbe che non possiamo più selezionare per costanza. In uno scenario di risoluzione dell'overload ordinario, la chiamata ora sarebbe ambigua perché normalmente il tipo restituito non parteciperà alla risoluzione dell'overload. Per le funzioni di conversione, tuttavia, esiste una backdoor. Se due funzioni di conversione sono ugualmente valide, il tipo restituito decide chi è il migliore in base a 13.3.3/1
. Pertanto, se si rimuove la const, verrà presa la prima, perché si B*
converte meglio in B*
che D*
in B*
.
Ora quale sequenza di conversione definita dall'utente è migliore? Quello per la seconda o la prima funzione di controllo? La regola è che le sequenze di conversione definite dall'utente possono essere confrontate solo se utilizzano la stessa funzione di conversione o costruttore secondo 13.3.3.2/3b2
. Questo è esattamente il caso qui: entrambi usano la seconda funzione di conversione. Si noti che quindi const è importante perché forza il compilatore a prendere la seconda funzione di conversione.
Dal momento che possiamo confrontarli, qual è il migliore? La regola è che la migliore conversione dal tipo di ritorno della funzione di conversione al tipo di destinazione vince (di nuovo da 13.3.3.2/3b2
). In questo caso, D*
converte meglio in D*
che in B*
. Così viene selezionata la prima funzione e riconosciamo l'eredità!
Si noti che poiché non abbiamo mai avuto bisogno di convertirci effettivamente in una classe base, possiamo quindi riconoscere l'ereditarietà privata perché se possiamo convertire da a D*
a a B*
non dipende dalla forma di ereditarietà secondo4.10/3
Se non sono correlati
Supponiamo ora che non siano correlati per eredità. Quindi per la prima funzione abbiamo i seguenti candidati
D* (Host<B, D>&)
E per il secondo ora abbiamo un altro set
B* (Host<B, D> const&)
Poiché non possiamo convertire D*
in B*
se non abbiamo una relazione di ereditarietà, ora non abbiamo una funzione di conversione comune tra le due sequenze di conversione definite dall'utente! Pertanto, saremmo ambigui se non fosse per il fatto che la prima funzione è un modello. I modelli sono la seconda scelta quando esiste una funzione non modello che è altrettanto buona secondo 13.3.3/1
. Quindi, selezioniamo la funzione non modello (seconda) e riconosciamo che non esiste eredità tra B
e D
!