2013-01-16 13 views
12

Si tratta di un errore del compilatore?Operatore nello spazio dei nomi che ne nasconde un altro nell'ambito globale

template <typename T> 
T& operator++(T& t) 
{ 
    return t; 
} 

namespace asdf { 

enum Foo { }; 
enum Bar { }; 

Foo& operator++(Foo& foo); 

void fun() 
{ 
    Bar bar; 
    ++bar; 
} 

} // end namespace asdf 

int main() 
{ 
    return 0; 
} 

Il messaggio di errore di 4,7 GCC è:

error: no match for 'operator++' in '++bar' 
note: candidate is: 
note: asdf::Foo& asdf::operator++(asdf::Foo&) 
note: no known conversion for argument 1 from 'asdf::Bar' to 'asdf::Foo&' 

Compila se commentare la riga:

Foo& operator++(Foo& foo); 
+1

[sì, è] (http://liveworkspace.org/code/2vreOi$0) .... –

+3

non la pensano così. VC++ genera lo stesso. – SChepurin

+1

@KarthikT: non sono sicuro di come il tuo codice collegato supporti l'argomento "è un bug". –

risposta

13

No che non è un bug. Ci sono tre gruppi paralleli di operatori considerati. Membri, operatori non membri e builtin.

Gli utenti non membri vengono cercati con una normale ricerca ADL non qualificata, ignorando tutte le funzioni dei membri della classe. Quindi l'operatore globale è nascosto da un lessico più vicino (e una funzione membro interposta non avrebbe nascosto altri non membri).

Nota che sovraccaricano risoluzione avviene dopo ricerca del nome ; nel tuo caso è stato trovato il nome operator++, ma nessun sovraccarico appropriato.

Se Bar era stata dichiarata a livello globale, e/o l'altro operatore nello spazio dei nomi asdf, ADL (nel primo caso) o di ricerca senza riserve ordinaria (in quest'ultimo caso) avrebbe trascinato l'operatore.


: Overload resolution (...) takes place after name lookup has succeeded. (C++ standard)

+0

Non sono sicuro se questo è abbastanza dettagliato. In caso di non corrispondenza, non dovrebbe essere cercato il prossimo spazio dei nomi chiuso? –

+1

@phresnel: Ma come il nome 'operator ++' forma una non corrispondenza per 'operator ++'? È solo il * nome * che è rilevante durante la ricerca del nome. –

+0

@phresnel, anche le dichiarazioni locali sono considerate. aggiornerà ... –

7

No, questo non è un bug del compilatore.

Esistono due ricerche di nomi che vengono eseguite per l'espressione ++bar.

  • La ricerca del nome regolare cerca gli scopi che racchiudono e spazi dei nomi fino a trovare la prima occorrenza di operator++. Questa ricerca funziona al rovescio, quindi lo spazio dei nomi globale viene cercato per ultimo. Quando si cercano le funzioni dell'operatore, le funzioni membro vengono trattate separatamente (e non interrompere questa ricerca).
  • La ricerca dipendente dall'argomento passa in coda e cerca le classi e gli spazi dei nomi aggiuntivi, ma solo quelli che sono correlati agli argomenti della funzione (operator++ in questo caso).

Nell'esempio della domanda, la ricerca normale trova asdf::operator++ e smette di cercare.
La ricerca dipendente dall'argomento aggiunge solo lo spazio dei nomi asdf alle posizioni da cercare, poiché questo è lo spazio dei nomi associato per enum Bar. Per questo motivo, non è possibile trovare il numero globale operator++.

È possibile trovare il valore globale operator++ con una dichiarazione using nello spazio nomi asdf.

+0

il primo punto elenco che descrivi non considera gli ambiti di classe. ovvero, anche se in una funzione membro della classe si utilizza un'espressione operatore, è possibile trovare un operatore dell'ambito dei nomi, anche in un ambito dello spazio dei nomi correlato a nonadl, nonostante vi sia un operatore membro con lo stesso nome. –

+0

@ JohannesSchaub-litb: È una modifica tra C++ 03 e C++ 11? Perché non riesco a trovare una tale eccezione in C++ 03 clausola 3.4.1 [basic.lookup.unqual]. –

+1

le regole sono specificate in 13.3.1.2 :-) –

1

Il sovraccarico si applica solo ai nomi definiti nello stesso ambito. Una volta che il compilatore trova un nome corrispondente, non guarda negli ambiti esterni, anche se il nome trovato si applica a qualcosa che non può essere usato. Questo non ha nulla a che fare con gli operatori; se il codice usa un nome di funzione nello stesso modo in cui usa l'operatore ++, otterrebbe lo stesso errore.Per esempio:

void f(int); 

struct C { 
void f(const C&); 
void g() { 
    f(3); // error: f(const C&) can't be called with argument 3 
}; 
Problemi correlati