Historia de la cuestión: ADL (Argument Dependent Lookup), también conocido como búsqueda de Koenig, apareció por primera vez en C++ para soportar la sobrecarga de operadores (especialmente operator<< y operator>> para tipos de usuario). El objetivo es encontrar correctamente las funciones al mezclar espacios de nombres y tipos de usuario.
Problema: El mecanismo estándar de búsqueda de funciones puede "no notar" una función si está declarada en un namespace diferente al punto de llamada. ADL resuelve este problema: el compilador considera el espacio de nombres de los tipos de los argumentos de la función para resolver los nombres. Este mismo mecanismo a veces puede llevar a una elección inesperada de sobrecarga o ambigüedades.
Solución: Cuando se llama a una función cuyos argumentos son objetos de espacios de nombres de usuario, el compilador busca las funciones sobrecargadas adecuadas no solo en el ámbito actual, sino también en todos los espacios de nombres relacionados con los tipos de los argumentos.
Ejemplo de código:
namespace lib { struct Widget {}; void do_something(const Widget&) { std::cout << "Widget" << std::endl; } } using lib::Widget; void call(const Widget& w) { do_something(w); // do_something se encuentra a través de ADL }
Características clave:
Si se declara una función con el mismo nombre en dos namespaces y se pasa un objeto del segundo, ¿cuál de ellas será llamada?
La función del espacio de nombres del argumento, si es adecuada según los argumentos, será seleccionada gracias a ADL:
namespace A { struct S {}; void f(const S&) { std::cout << "A!"; } } namespace B { struct S {}; void f(const S&) { std::cout << "B!"; } } A::S a; B::S b; f(a); // llamará a A::f a través de ADL f(b); // llamará a B::f a través de ADL
¿Funciona ADL con funciones plantilla?
Sí, si la función plantilla está definida en el namespace que coincide con el tipo de argumento, ADL la encontrará al invocarla con este tipo.
¿Funciona ADL para punteros a funciones?
No, ADL no se aplica al obtener un puntero a una función (por ejemplo, al tomar su dirección). Solo en la invocación directa de la función.
El proyecto incorporó varias bibliotecas de terceros, donde cada namespace tenía su propio print(). En el código principal se utilizaba print() con objetos de diferentes clases. Debido a ADL, el compilador comenzó a "elegir" la función del espacio de nombres equivocado.
Ventajas:
Desventajas:
Uso de llamada calificada (especificación explícita del namespace):
lib::do_something(w); // ¡Explícitamente!
Ventajas:
Desventajas: