2015-02-07 11 views
5

Cercando di capire perché nessun sovraccarico ambiguità causata nelle seguenti codici:Pass di sovraccarico riferimento/valore

float foo2(float& i) 
{ 
    cout << "call from reference" << endl; 
    return i; 
} 
float foo2(float i) 
{ 
    cout << "call from non reference"<<endl; 
    return i; 
} 
int main() 
{ 
    cout<<foo2(2); // print "call from non reference" 
} 

Il foo2 cui parametri non passati per riferimento viene chiamato. Perché? Come chiamare il foo2 che passa i parametri di riferimento?

+1

_ "Come chiamare il foo2 che passa i parametri di riferimento?" _ Dargli un riferimento? –

+0

[Il compilatore si lamenterà dell'ambiguità] (http://ideone.com/W5eLdq) se stai tentando di utilizzare la chiamata ambigua. –

+0

Grazie a tutti, il problema risolto – kchpchan

risposta

2

Il 2 assegnato come parametro per foo2 è un valore rvalore, che non può essere un riferimento. Quindi la funzione che accetta un riferimento non può essere chiamata con esso.

+0

'2' non è un riferimento di rvalue, è un valore di rvalue. Può * legare * a un riferimento di rvalue. (Il codice nella domanda non presenta ambiguità, dovresti cambiare la prima funzione in 'const int e' t ocre ambiguity.) –

+0

@remyabel Oh hai ragione, risolto. – emlai

5

Il foo2 cui parametri non passato per riferimento è chiamato. Perché?

Perché non è possibile passare una costante o qualsiasi espressione calcolata facendo riferimento a una funzione che prende un riferimento non costante. Per passare un'espressione per riferimento è necessario un valore assegnabile - qualcosa che può apparire sul lato sinistro di un'espressione di assegnazione. Poiché 2 non può essere visualizzato sul lato sinistro di un'espressione di assegnazione, non può essere utilizzato per chiamare una funzione che si aspetta un riferimento. Quando il riferimento è const, è possibile passare qualsiasi cosa, poiché C++ creerà una variabile temporanea, assegnerà l'espressione ad essa e passerà un riferimento alla funzione che utilizza il riferimento const.

Come chiamare il foo2 che passa i parametri di riferimento?

Non esiste un modo ovvio di farlo, perché nel momento in cui passa una variabile o un'altra espressione che può diventare un punto di riferimento, il compilatore si lamenterà che si stanno facendo una chiamata ambigua:

float f; 
foo2(f); // <<== This will not compile 

C'è un modo per chiamare, però: si può fare un puntatore a funzione che corrisponde solo a una delle due firme di funzione, e utilizzarlo per effettuare la chiamata:

typedef float (*fptr_with_ref)(float&); 

int main() 
{ 
    cout<<foo2(2) << endl; // print "call from non reference" 
    fptr_with_ref foo2ptr(foo2); // Only one overload matches 
    float n = 10; 
    cout<<foo2ptr(n) << endl; // Calls foo2(float&) 
} 

Demo.

+0

È interessante notare che 'int f; foo2 (f); 'compilerà e comporterà una chiamata alla funzione non di riferimento (appena provato). Anche se non posso dire perché. (** Modifica ** ha annullato una modifica perché @dasblinkenlight ha risposto di seguito, grazie) – jadhachem

+1

@jadhachem Perché il compilatore effettua una chiamata come questa: 'foo2 ((float) f)'. Dato che 'f' deve essere convertito da' int' a 'float', non c'è ambiguità. Se crei 'f' a' float', vedrai l'ambiguità. – dasblinkenlight

+0

@dasblinkenlight, grazie per la tua risposta. Concetto chiarito. La tua risposta non è apparsa prima di aggiornare la pagina. – kchpchan

1

La tua domanda è in termini C++, non in termini di progettazione. C++ supporta le cose in un modo perché ha senso in termini di design. Il C++ ti permette di fare molte cose, ma se vuoi fare del buon software con esso non puoi limitarti a semplici regole C++ letterali, devi andare oltre. In pratica significa che finisci per creare le tue regole.

Nel tuo caso, beh, non sceglierei mai la variante di riferimento se non avessi effettivamente modificato la variabile nella funzione.

Se si adottano tali "regole" per se stessi, allora si vede immediatamente perché la funzione ref non si lega: qual è il punto, in primo luogo, di cambiare una costante allentata?

Se si apportano le giuste regole, si vedrà che sono splendidamente supportate dal C++. Come ... la funzione cambia un oggetto: passa il riferimento non const. Nessun cambiamento? const ref. Opzionale? puntatore const. Acquisisci la gestione dei mem? puntatore non-const.

Si noti che questo è solo l'inizio, soprattutto quando entra in gioco il multi-threading. Devi aggiungere cose al "contratto" della funzione. Esempio per const ref: l'oggetto deve rimanere 'vivo' dopo la chiamata? L'oggetto può cambiare durante la chiamata? E così via.