c++ - Comportamiento interesante del compilador con espacios de nombres
compiler-errors namespaces (3)
Cuando el código f(a)
, el compilador encuentra la función void f(A a){}
en el namespace X
debido a la ADL (búsqueda dependiente del argumento, también conocida como búsqueda de Koenig ).
A
se declara en el espacio de nombres X
, por lo tanto, cuando el compilador necesita buscar la definición de f
, incluye posibilidades de ese espacio de nombres porque el objeto a
de tipo A
está en ese espacio de nombres (como se declara X::A a;
).
Por otro lado, int
no se declara en el namespace X
, por lo que el namespace X
no se incluye en la búsqueda. Como no se encuentra la función correspondiente para f
, no se puede compilar.
Supongamos el siguiente código:
#include <iostream>
using namespace std;
namespace X
{
class A{};
void f(A a){}
void g(int a){}
}
int main()
{
X::A a;
f(a);
g(5);
}
Cuando compilo el código, ocurre el siguiente error de compilación:
main.cpp: en la función ''int main ()'':
main.cpp: error: ''g'' no se declaró en este ámbito
Entonces, la función f
se compila perfectamente, pero g
no. ¿Cómo? Ambos pertenecen al mismo espacio de nombres. ¿El compilador deduce que la función f
pertenece al espacio de nombres X
del argumento de tipo X::A
? ¿Cómo se comporta el compilador en tales casos?
Esto funciona para la expresión de llamada de función:
f(a);
debido a que el espacio de nombres al que pertenece X::A
se incluye en la búsqueda de la función f
debido a la búsqueda dependiente del argumento ( ADL ) , cppreference explica ADL de la siguiente manera:
La búsqueda dependiente de argumentos, también conocida como ADL o búsqueda de Koenig, es el conjunto de reglas para buscar los nombres de las funciones no calificadas en las expresiones de llamadas a funciones, incluidas las llamadas de funciones 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 habitual de nombres no calificados.
La búsqueda dependiente de argumentos hace posible usar operadores definidos en un espacio de nombres diferente
Esto está cubierto en el borrador de la sección estándar de C ++ 3.4.2
Búsqueda de nombre dependiente del argumento :
Cuando la expresión postfix en una llamada a función (5.2.2) es una identificación no calificada, se pueden buscar otros espacios de nombres no considerados durante la búsqueda no calificada habitual (3.4.1), y en esos espacios de nombres, función o función amiga del ámbito de nombres de espacio las declaraciones de plantilla (11.3) no visibles pueden encontrarse
y continúa diciendo:
Para cada argumento de tipo T en la llamada a función, hay un conjunto de cero o más espacios de nombres asociados y un conjunto de cero o más clases asociadas a considerar. Los conjuntos de espacios de nombres y clases están determinados por completo por los tipos de argumentos de función (y el espacio de nombres de cualquier argumento de plantilla de plantilla).
e incluye la siguiente viñeta:
Si T es un tipo de clase (incluidas las uniones), sus clases asociadas son: la clase misma; la clase de la que es miembro, si la hay; y sus clases base directas e indirectas. Sus espacios de nombres asociados son los espacios de nombres de los cuales sus clases asociadas son miembros . [...]
y más abajo proporciona un ejemplo similar a su problema:
namespace NS {
class T { };
void f(T);
void g(T, int);
}
NS::T parm;
void g(NS::T, float);
int main() {
f(parm); // OK: calls NS::f
extern void g(NS::T, float);
g(parm, 1); // OK: calls g(NS::T, float)
}
La expresión de llamada de función:
g(5);
no funciona porque ADL no agrega espacios de nombres para argumentos que son tipos fundamentales.
Herb Sutter cubre ADL en Gotw # 30 y en ¿Qué hay en una clase? - El Principio de la interfaz .
X::A a;
f(a);
funciona debido a la búsqueda dependiente del argumento (también conocida como búsqueda Koenig). a
es un objeto de la clase A
dentro del espacio de nombres X
, cuando el compilador busca una función compatible con f
, buscará el espacio de nombres X
en este caso. Consulte Argumento dependiente de búsqueda para obtener más información.