6

Tengo dos fragmentos para ADL con fines de demostración. Ambos fragmentos han sido compilados por VC10, gcc & comeau C++ compiladores, y el resultado es el mismo para los tres.¿Por qué ADL tiene prioridad sobre una función en 'espacio de nombres estándar' pero es igual a la función en el espacio de nombres definido por el usuario?

< 1> ADL contra el uso de la directiva de un espacio de nombres de usuario definidos:

#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); 
} 

Compilar resultado:

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] 

Se espera que ADL no tiene prioridad sobre el resultado normal de búsqueda además de que ADL no es un ciudadano de segunda clase, el resultado de la búsqueda de ADL está vinculado con la búsqueda no igualada normal (sin ADL). Es por eso que tenemos la ambigüedad.

< 2> ADL contra el uso de Directiva de espacio de nombres 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); 
} 

Ésta compila bien.

El resultado es que el compilador elige el resultado de ADL (toma precedente de std :: swap), lo que significa que se llamará N::swap() al 'punto 1'. Solo cuando está ausente el 'punto 1' (por ejemplo, si comento esa línea), la compilación usará el retroceso std::swap.

Nota esta forma se ha utilizado en muchos lugares como una forma de sobrescribir el std::swap. Pero mi pregunta es, ¿por qué ADL tiene prioridad sobre 'std namespace' (case2) pero se considera igual a la función de espacio de nombres definida por el usuario (case1)?

¿Hay un párrafo en el estándar C++ que diga eso?

============================================== ================================ Editar después de leer las respuestas útiles, puede ser útil para los demás.

Así que modifiqué mi fragmento 1 & ahora la ambigüedad se ha ido y la compilación aparentemente prefiere la función Nontemplate al hacer una resolución de sobrecarga.

#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() 
} 

También he modificado mi fragmento 2. ¡Solo para que la ambigüedad parezca solo por diversión!

#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 y Comeau ambos dicen ambigüedad como se esperaba:

"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 &)" 

Por cierto VC10 estúpida como siempre vamos a éste pase bien, a no ser que se quita el 'std :: intercambio'.

Sólo un poco más que escribir: C++ sobrecarga puede ser complicado (30+ página en C++ estándar), pero al appendlix B hay una de 10 páginas muy legible allí ...

Gracias por todo el buen entradas, ahora está claro.

Respuesta

9

Su prueba no verifica si ADL tiene prioridad o no sobre la búsqueda habitual, sino cómo la resolución de sobrecarga determina la mejor coincidencia. El motivo por el que funciona el segundo caso de prueba es que std::swap es una plantilla, y cuando se realiza una resolución de sobrecarga en una coincidencia perfecta (encontrada por ADL) y una plantilla, la función sin plantilla tiene prioridad.

+0

El punto a destacar es que ADL corresponde a * name searchup *, y name searchup no tiene noción de "precedence". –

+0

@KerrekSB: Creo que David estaba hablando de la etapa de búsqueda de nombres en una resolución de sobrecarga, que trata de elegir la mejor opción. – Gob00st

12

Una llamada a la función que ocurre en varias etapas :

  1. búsqueda de nombre -> pone funciones candidatas en una llamada sobrecarga de establecer
    • esta es la parte en la ADL sucede si tener una búsqueda de nombre no calificada
  2. deducción de argumento de plantilla -> para cada plantilla en el conjunto de sobrecarga
  3. resolución de sobrecarga -> elegir el mejor partido

Estás confundiendo la parte 1 con la parte 3. La búsqueda de nombre en realidad se puso las dos swap funciones en el conjunto de sobrecarga ({N::swap, std::swap}), pero la parte 3 decidirá, lo cual uno para llamar al final.

Ahora, ya std::swap es una plantilla, y la norma dice que las funciones no de plantilla son más especializado de funciones de plantilla cuando se hace la resolución de sobrecarga, sus <2> llamadas N::swap:

§13.3.3 [over.match.best] p1

Dadas estas definiciones, una función viable F1 se define como una función mejor que otra función viable F2 si [...]

  • F1 es una función no-plantilla y F2 es una especialización de plantilla de función [...]

† recomiendo los tres primeros videos de this excellent series sobre el tema.

+0

Así que, comenten el voto a favor por favor? – Xeo

+0

¡Gracias por la referencia estándar! – Gob00st

+0

@Xeo: dunno (con respecto al voto a la baja), la primera frase me confundió un poco, porque el compilador no encuentra * todas * las funciones que podrían llamarse. La búsqueda de nombres se trata solo de encontrar un subconjunto. –

Cuestiones relacionadas