6

Ho due snippet per ADL a scopo dimostrativo. Entrambi i frammenti sono stati compilati da VC10, gcc & compilatori C++ di comeau, e il risultato è lo stesso per tutti e tre.Perché ADL ha la precedenza su una funzione in "spazio dei nomi std" ma è uguale alla funzione nello spazio dei nomi definito dall'utente?

< 1> ADL contro direttiva using di un utente namespace definito:

risultato
#include <algorithm> 
namespace N 
{ 
    struct T {}; 
    void swap(T,T) {} 
} 

namespace M 
{ 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using M::swap; 
    N::T o1,o2; 
    swap(o1,o2); 
} 

Compile:

error C2668: 'M::swap' : ambiguous call to overloaded function 
could be 'void M::swap(N::T,N::T)' 
or  'void N::swap(N::T,N::T)' [found using argument-dependent lookup] 

Questo è previsto come ADL non ha la precedenza sopra il normale risultato di ricerca più ADL non è cittadino di 2a classe, il risultato della ricerca ADL è unito alla normale ricerca non richiesta (non ADL). Ecco perché abbiamo l'ambiguità.

< 2> ADL contro l'uso di direttiva del namespace std:

#include <algorithm> 
namespace N 
{ 
    struct T {}; 
    void swap(T,T) {} //point 1 
} 

namespace M 
{ 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using std::swap; 
    N::T o1,o2; 
    swap(o1,o2); 
} 

Questo compila ok.

Il risultato è il compilatore scegliere il risultato ADL (ha la precedenza rispetto a std :: swap), ovvero verrà chiamato N::swap() al 'punto 1'. Solo quando nell'assenza del 'punto 1' (diciamo se commento quella riga), la compilazione userà invece la caduta std::swap.

Nota in questo modo è stato utilizzato in molti posti come un modo per sovrascrivere il std::swap. Ma la mia domanda è, perché ADL ha la precedenza su 'std namespace' (caso2) ma è considerato uguale alla funzione namespace definita dall'utente (caso1)?

Esiste un paragrafo nello standard C++ che lo dice?

========================================= =================================== Modifica dopo aver letto le risposte utili, potrebbe essere utile per gli altri.

Quindi ho modificato il mio snippet 1 & ora l'ambiguità è scomparsa e compilare apparentemente preferisce la funzione Nontemplate quando si esegue la risoluzione di sovraccarico!

#include <algorithm> 
namespace N 
{ 
    struct T {}; 
    void swap(T,T) {} 
} 

namespace M 
{ 
    template<class T> 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using M::swap; 
    N::T o1,o2; 
    swap(o1,o2); //here compiler choose N::swap() 
} 

Ho anche ottimizzato il mio snippet 2. Solo per far apparire l'ambiguità solo per divertimento!

#include <algorithm> 
namespace N 
{ 
    struct T {}; 

    template<class _Ty> inline 
    void swap(_Ty& _Left, _Ty& _Right) 
    { 
     _Ty _Tmp = _Move(_Left); 
     _Left = _Move(_Right); 
     _Right = _Move(_Tmp); 
    } 
} 

namespace M 
{ 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using std::swap; 
    N::T o1,o2; 
    swap(o1,o2); 
} 

gcc e Comeau entrambi dicono ambiguità come previsto:

"std::swap" matches the argument list, the choices that match are: 
      function template "void N::swap(_Ty &, _Ty &)" 
      function template "void std::swap(_Tp &, _Tp &)" 

BTW VC10 stupido come al solito facciamo questo passaggio ok a meno che non posso rimuovere la 'utilizzando std :: di swap'.

Solo un po 'di più a scrivere: C++ sovraccarico può essere difficile (30+ pagina in C++ standard), ma a appendlix B di v'è un molto leggibile 10 pagina ci ...

Grazie per tutto il bello input, ora è chiaro.

risposta

9

Il test non verifica se ADL ha la precedenza o meno rispetto alla normale ricerca, ma piuttosto come la risoluzione di sovraccarico determina la corrispondenza migliore. La ragione per cui il secondo caso di test funziona è che std::swap è un modello e quando si esegue la risoluzione di sovraccarico su una corrispondenza perfetta (trovata da ADL) e un modello, la funzione senza modelli ha la precedenza.

+0

Il punto degno di nota è che ADL riguarda * lookup *, e la ricerca del nome non ha la nozione di "precedenza". –

+0

@ KerrekSB: Penso che David stia parlando di una fase di ricerca del nome in fase di sovraccarico, il che significa scegliere la migliore corrispondenza. – Gob00st

12

Una chiamata di funzione avviene in più fasi :

  1. ricerca del nome -> mette funzioni candidate in un cosiddetto sovraccarico impostare
    • questa è la parte in cui ADL succede se si avere una ricerca nome non qualificata
  2. deduzione argomento argomento -> per ogni modello nel set di sovraccarico
  3. risoluzione di sovraccarico -> scegliere la migliore corrispondenza

Stai confondendo parte 1 con la parte 3. La ricerca del nome sarà effettivamente mettere entrambe swap funzioni nel set di sovraccarico ({N::swap, std::swap}), ma parte 3 deciderà che uno da chiamare alla fine.

Ora, dal momento che std::swap è un modello, e la norma dice che le funzioni non-modello sono più specializzati di funzioni template quando si fa la risoluzione di sovraccarico, i tuoi <2> chiamate N::swap:

§13.3.3 [over.match.best] p1

Date queste definizioni, una funzione valida F1 è definita come una funzione migliore di un'altra funzione valida F2 se [...]

  • F1 è una funzione non-modello e F2 è una funzione di modello di specializzazione [...]

† vi consiglio i primi tre video di this excellent series sull'argomento.

+0

Quindi, commentare il downvote per favore? – Xeo

+0

Grazie per il riferimento standard! – Gob00st

+0

@Xeo: non so (riguardo al downvote), la prima frase mi ha confuso un po ', perché il compilatore non trova * tutte * le funzioni che potrebbero essere chiamate. La ricerca dei nomi riguarda solo la ricerca di un sottoinsieme. –

Problemi correlati