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.
Il punto degno di nota è che ADL riguarda * lookup *, e la ricerca del nome non ha la nozione di "precedenza". –
@ 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