13

Considerate codice semplice:risoluzione di sovraccarico con molteplici funzioni e molteplici operatori di conversione

#include<iostream> 

struct A { 
    operator double(){ 
     std::cout<<"Conversion function double chosen."<<std::endl; 
     return 1.1; 
    } 
    operator char(){ 
     std::cout<<"Conversion function char chosen."<<std::endl; 
     return 'a'; 
    } 
} a; 

void foo(int){} 
void foo (char){} 
int main() { 
    foo(a); 
} 

Sopra codice funziona bene, e come previsto gcc, clang e VC++ sceglie foo(char).

Ora consente di modificare il codice po ':

#include<iostream> 

struct A { 
    operator double(){ 
     std::cout<<"Conversion function double chosen."<<std::endl; 
     return 1.1; 
    } 
    operator char(){ 
     std::cout<<"Conversion function char chosen."<<std::endl; 
     return 'a'; 
    } 
} a; 

void foo(int){} 
void foo (double){} //parameter changed from char to double 
int main() { 
    foo(a); 
} 

Ora questo dovrebbe avere scegliere foo(double), ma sembra solo VC++ è felice con il codice mentre clang e gcc sono infelici con il codice di cui sopra.

main.cpp:11:10: error: call of overloaded 'foo(A&)' is ambiguous 
foo(a); 
    ^
main.cpp:8:6: note: candidate: void foo(int) 
void foo(int){} 
    ^
main.cpp:9:6: note: candidate: void foo(double) 
void foo (double){} //parameter changed from char to double 
    ^

Qualcuno può spiegare perché il codice di cui sopra non riesce? o è un bug?

Un'altra domanda: codice di condivisione gcc e clang della risoluzione di sovraccarico?

+2

1: definire "infelice". 2: Cosa succede se rimuovi 'foo (int)'? – Amit

+2

@Amit il codice di mezzo infelice viene rifiutato, e come per la rimozione della funzione 'pippo (int)', non fa parte della domanda, puoi provarlo tu stesso per favore. –

+1

@AngelusMortis: quale funzione sceglie VC++? – davidhigh

risposta

4

TL; DR: La differenza è che nel primo caso, a differenza del secondo, le sequenze di conversione definite dall'utente (A -> char, A -> int) chiamano la stessa funzione di conversione (operator char). Ciò ci consente di rompere il legame tramite [over.ics.rank]/(3.3).


Le migliori operatori di conversione per particolari funzioni sono selezionati per [over.match.best]/(1.4) (confrontando le sequenze di conversione dal loro tipo di ritorno).

qui la funzione di conversione migliore per foo(int) è operator char seguita da una promozione per int, al contrario di operator double seguita da una conversione in virgola mobile.

Ora consideriamo entrambe le varianti del secondo overload:

  1. Le migliori ICS per foo(char) è anche tramite operator char (identità meglio di conversione in virgola mobile).Così [over.ics.rank]/(3.3) è applicabile:

    definita dall'utente sequenza conversione U1 è una migliore sequenza conversione di un'altra sequenza di conversione definita dall'utente U2se contengono la stessa funzione di conversione definita dall'utente [...] e in entrambi i casi la la seconda sequenza di conversione standard di U1 è migliore della seconda sequenza di conversione standard di U2.

    Quindi la conversione complessiva a F2 è considerata migliore ed è selezionata.

  2. Il miglior ICS per foo(double) è via operator double. Finiamo con due sequenze di conversione che impiegano funzioni di conversione distinte; nulla si applica veramente e otteniamo solo un'ambiguità.

5

A -> char è A -> char.

A -> int è A -> char -> int (perché char a int è una promozione e quindi batte la conversione double a int).

A -> double è A -> double.

Due sequenze di conversione definite dall'utente sono paragonabili solo se coinvolgono la stessa funzione di conversione definita dall'utente. Pertanto, A -> char è una sequenza di conversione migliore di A -> int, quindi il tuo primo caso non è ambiguo. Né A -> intA -> double è migliore dell'altro, quindi il secondo caso è ambiguo.