Espacios de nombres
Variantes
Acciones

Búsqueda dependiente de argumento

De cppreference.com
< cpp‎ | language

La búsqueda dependiente de argumento, también conocida como ADL (por sus siglas del inglés Argument-Dependent Lookup), o búsqueda de Koenig [1], es el conjunto de reglas para buscar los nombres de función no calificados en las expresiones de llamada a función, incluyendo llamadas a función implícitas a operadores sobrecargados. Estos nombres de función se buscan en los espacios de nombres de sus argumentos además de los ámbitos y espacios de nombres considerados por la búsqueda de nombre no calificado habitual.

La búsqueda dependiente de argumento hace posible el uso de operadores definidos en un espacio de nombres distinto. Ejemplo:

#include <iostream>
int main()
{
    std::cout << "Prueba\n"; // No hay operator<< en el espacio de nombres global, pero ADL
                           // examina el espacio de nombres std porque el argumento izquierdo está en
                           // std y encuentra a std::operator<<(std::ostream&, const char*)
    operator<<(std::cout, "Prueba\n"); // lo mismo, usando la notación de llamada a función
 
    // sin embargo,
    std::cout << endl; // ERROR: 'endl' no está declarado en este espacio de nombres.
                       // Esto no es una llamada a función a endl(), así que ADL no aplica
 
    endl(std::cout); // de acuerdo: esta es una llamada a función: ADL examina el espacio de nombres std
                     // porque el argumento de endl está en std, y encuentra a std::endl
 
    (endl)(std::cout); // ERROR: 'endl' no está declarado en este espacio de nombres.
                       // La subexpresión (endl) no es una expresión de llamada a función
}


Contenido

[editar] Detalles

Primero, la búsqueda dependiente de argumento no se considera si el conjunto de búsqueda producido por la búsqueda no calificada habitual contiene alguno de los siguientes:

1) una declaración de una clase miembro;
2) una declaración de una función en un ámbito de bloque (que no es una declaración using);
3) cualquier declaración que no sea una función o una plantilla de función (por ejemplo, un objeto función u otra variable cuyo nombre entre en conflicto con el nombre de la función que se está buscando).

De lo contrario, para cada argumento en una expresión de llamada a función, se examina su tipo para determinar el conjunto asociado de espacios de nombres y clases que se agregará a la búsqueda.

1) Para los argumentos de tipos fundamentales, el conjunto asociado de espacios de nombres y clases está vacío.
2) Para los argumentos de tipo clase (incluida union), el conjunto consta de:
a) la clase misma;
b) todas sus clases base directas e indirectas;
c) si la clase es un miembro de otra clase, la clase de la cual es miembro;
d) los espacios de nombres circundantes más internos de las clases agregadas al conjunto;
3) Para los argumentos cuyo tipo es una especialización de plantilla de clase, además de las reglas de clase, se examinan los siguientes tipos y sus clases asociadas y espacios de nombres se agregan al conjunto.
a) Los tipos de todos los argumentos de plantilla suministrados para tipos parámetros de plantilla (omitiendo los parámetros de plantilla de no-tipo y omitiendo los parámetros de plantilla de plantilla).
b) Los espacios de nombres en los que los argumentos de plantilla de plantilla son miembros.
c) Las clases en las que los argumentos de plantilla de plantilla son miembros (si resultan ser plantillas de miembros de clase)
4) Para los argumentos de tipo enumeración, se agrega al conjunto el espacio de nombres circundante más interno de la declaración del tipo enumeración. Si el tipo enumeración es miembro de una clase, esa clase se agrega al conjunto.
5) Para los argumentos de tipo puntero a T o puntero a un array de T, se examina el tipo T y su conjunto asociado de clases y espacios de nombres se agrega al conjunto.
6) Para los argumentos de tipo función, se examinan los tipos de parámetros de función y el tipo de retorno de la función y su conjunto asociado de clases y espacios de nombres se agrega al conjunto.
7) Para los argumentos de tipo puntero a función miembro F de clase X, los tipos de parámetro de función, el tipo de retorno de la función, y la clase X se examinan y su conjunto asociado de clases y espacios de nombres se agregan al conjunto.
8) Para los argumentos de tipo puntero a dato miembro T de clase X, el tipo de miembro y el tipo X se examinan y su conjunto asociado de clases y espacios de nombres se agrega al conjunto.
9) Si el argumento es el nombre o la expresión dirección-de para un conjunto de funciones sobrecargadas (o plantillas de función), cada función en el conjunto de sobrecarga se examina y su conjunto asociado de clases y espacios de nombres se agrega al conjunto.
  • Además, si el conjunto de sobrecargas se nombra mediante un id-de-plantilla, todos los argumentos de su tipo y los argumentos de plantilla de plantilla (pero no los argumentos de plantilla de no-tipo) se examina y su conjunto asociado de clases y espacios de nombres se agrega al conjunto.

Si algún espacio de nombres en el conjunto asociado de clases y espacios de nombres es un espacio de nombres en línea, su espacio de nombres circundante también se agrega al conjunto.

Si algún espacio de nombres en el conjunto asociado de clases y espacios de nombres contiene directamente un espacio de nombres en línea, ese espacio de nombres en línea se agrega al conjunto.

(desde C++11)

Una vez que se determina el conjunto asociado de clases y espacios de nombres, todas las declaraciones que se encuentran en las clases de este conjunto se descartan con el propósito de un procesamiento ADL adicional, excepto las funciones amigas en el ámbito del espacio de nombres y las plantillas de función, como se indica en el punto 2 a continuación.

El conjunto de declaraciones encontradas por la búsqueda no calificada ordinaria y el conjunto de declaraciones que se encuentran en todos los elementos del conjunto asociado producido por ADL, se fusionan, con las siguientes reglas especiales:

1) se ignoran las directivas using en los espacios de nombres asociados;
2) las funciones amigas en el ámbito del espacio de nombres (y las plantillas de función) que se declaran en una clase asociada son visibles a través de ADL incluso si no son visibles a través de la búsqueda ordinaria;
3) se ignoran todos los nombres, excepto para las funciones y plantillas de función (no hay colisión con las variables).

[editar] Notas

[editar] Ejemplos

Ejemplo de http://www.gotw.ca/gotw/030.htm

namespace A {
      struct X;
      struct Y;
      void f(int);
      void g(X);
}
 
namespace B {
    void f(int i) {
        f(i);   // llama a B::f (recursión infinita)
    }
    void g(A::X x) {
        g(x);   // ERROR: ambiguo entre B::g (búsqueda ordinaria)
                //        y A::g (búsqueda dependiente de argumento)
    }
    void h(A::Y y) {
        h(y);   // llama a B::h (recursión infinita): ADL examina el espacio de nombres A
                // pero no encuentra ninguna A::h, así que solo se usa B::h
                // de la búsqueda ordinaria
    }
}


[editar] Véase también

[editar] Referencias

  1. Andrew Koenig: "Una nota personal acerca de la búsqueda dependiente de argumento"