2014-09-17 16 views
11

Ho codice seguente:Perché chiamare una funzione non membro con lo stesso nome di una funzione membro genera un errore

void f(int){} 

struct A 
{ 
    void f() 
    { 
     f(1); 
    } 
}; 

Questo codice non è ben-formato con il messaggio di errore (GCC): error: no matching function for call to ‘A::f(int)’ o (clang) Too many arguments to function call, expected 0, have 1; did you mean '::f'?

Perché ho bisogno di usare :: per chiamare la funzione non-membro con lo stesso nome della funzione di membro, ma con la firma di diverso? Qual è la motivazione per questo requisito?

Penso che il compilatore dovrebbe essere in grado di capirlo Voglio chiamare la funzione non membro in quanto la firma è diversa (clang mette anche quello nel messaggio di errore!).

Si prega di non segnare questa come duplicato - si tratta di una questione diversa da questo Calling in C++ a non member function inside a class with a method with the same

+0

Poiché risoluzione di ambito è separato dal, e eseguita prima, la risoluzione di sovraccarico. – Sneftel

+0

Dai uno sguardo allo standard, in particolare §3.4.1 [basic.lookup.unqual] – WhozCraig

risposta

18

Perché ho bisogno di usare :: per chiamare la funzione non-membro con lo stesso nome della funzione di membro, ma con firma diversa

Perché queste sono le regole. I nomi in uno scope nidificato nascondono entità con lo stesso nome in un ambito più ampio.

Qual è la motivazione per questo requisito?

Si consideri il caso in cui una funzione di membro chiama un altro utente con una firma che non corrispondono del tutto:

struct A { 
    void f(double); 
    void g() {f(42);} // requires int->double conversion 
}; 

Ora supponiamo che qualcuno aggiunge una funzione isolata nello spazio dei nomi che circonda

void f(int); 

Se questo fosse incluso nel set di sovraccarichi nell'ambito di A, allora improvvisamente il comportamento di A::g cambierebbe: lo chiamerebbe invece di A::f. La limitazione del sovraccarico ai nomi nel più stretto ambito disponibile impedisce questo tipo di rottura inaspettata.

Come tu (e il tuo utile compilatore) dì, il nome esterno è ancora disponibile (con qualifica) se ne hai bisogno.

+0

+1 per l'esempio pratico. – legends2k

7

Il compilatore esegue la ricerca del nome qualificato, per f, specificato nel §3.4.1 [basic.lookup.unqual] (per fortuna , non c'è ADL qui):

1 in tutti i casi elencati nel 3.4.1, gli scopi vengono cercati una dichiarazione nell'ordine indicato in ciascuna delle rispettive categorie; La ricerca del nome termina non appena viene trovata una dichiarazione per il nome. Se non viene trovata alcuna dichiarazione , il programma è mal formato.

8 Ai membri di una classe X, un nome usato in un corpo funzione membro , in un argomento standard, in un specifica delle eccezioni, nel tutore o uguale-inizializzatore di un membro non statico di dati (9.2), o nella definizione di un membro della classe di fuori della definizione di X, seguente dichiaratore-id del membro, sono dichiarate in una delle seguenti modi:

  • bef di minerale suo impiego nel blocco in cui viene utilizzato o in un blocco che contiene (6.3), o
  • deve essere un membro della classe X o essere un membro di una classe di base di X (10.2), o
  • se X è una classe nidificata di classe Y (9.7), è membro di Y, o deve essere un membro di una classe base di Y (questa ricerca applica a sua volta Y 's racchiudono classi, iniziando con il più interno racchiude classe), o
  • se X è una classe locale (9.8) o è una classe nidificata di una classe locale, prima della definizione di classe X in un blocco che racchiude la definizione di classe X, o
  • se X è un membro del namespace N, o è una classe annidata di una classe che è un membro di N, o è una classe locale o una classe nidificata all'interno una classe locale di una funzione membro di N, prima dell'uso di il nome, nello spazio dei nomi N o in uno dei namespace di inclusione di N.

La ricerca del nome si interrompe non appena viene trovata una dichiarazione. Quindi, una volta trovato il membro f() al secondo punto, si ferma e non cerca mai altrove.

Il rifiuto delle funzioni non modificabili viene eseguito dopo la ricerca del nome, a risoluzione di sovraccarico.

1

Perché devo usare :: per chiamare la funzione non membro con lo stesso nome della funzione membro, ma con firma diversa? Qual è la motivazione per questo requisito?

Questo è il punto principale di avere spazi dei nomi. Un nome locale (più vicino) è preferito e più visibile su un nome globale. Poiché un struct è di nuovo un ambito, il suo f ombreggia la visibilità di ::f. Quando devi avere quello globale, devi dire che lo fai. Perché?

Questa funzione viene fornita per garantire che sia possibile chiamare in modo pacifico le funzioni definite assumendo che vengano richiamate e quando ne occorra uno da un diverso spazio dei nomi, ad esempio la libreria standard, lo si specifica esplicitamente, ad esempio std:: . È solo una forma pulita di disambiguazione, senza lasciare spazio alla possibilità di fare la sua parte.

0

di capire il motivo del vostro errore e perché è necessario utilizzare in modo esplicito la sintassi ::f(), si può prendere in considerazione alcuni aspetti del C++ processo di compilatore:

La prima cosa che fa il compilatore è ricerca del nome .

La ricerca del nome non qualificato inizia dall'ambito corrente e quindi si sposta all'esterno; si interrompe non appena trova una dichiarazione per il nome della funzione, anche se successivamente tale funzione sarà determinata a non essere un candidato valido per la chiamata di funzione.

Quindi, la risoluzione di sovraccarico viene eseguita sull'insieme delle funzioni individuate dal nome ricerca.

(E, infine, controllo accesso viene eseguita la funzione che sovraccaricano risoluzione raccolto.)

Problemi correlati