¿Cuáles son algunas buenas explicaciones sobre qué argumento depende de la búsqueda? Muchas personas también lo llaman Koenig Lookup también.
Preferiblemente me gustaría saber:
- ¿Por qué es algo bueno?
- ¿Por qué es algo malo?
- ¿Como funciona?
c++
argument-dependent-lookup
name-lookup
c++-faq
usuario965369
fuente
fuente
std::cout << "Hello world";
no compilaríaRespuestas:
La búsqueda de Koenig , o búsqueda dependiente de argumentos , describe cómo el compilador busca en C ++ nombres no calificados.
El estándar C ++ 11 § 3.4.2 / 1 establece:
En términos más simples, Nicolai Josuttis afirma 1 :
Un ejemplo de código simple:
En el ejemplo anterior, no hay una
using
declaración ni unausing
directiva, pero el compilador identifica correctamente el nombre no calificadodoSomething()
como la función declarada en el espacioMyNamespace
de nombres mediante la aplicación de búsqueda de Koenig .¿Como funciona?
El algoritmo le dice al compilador que no solo mire el alcance local, sino también los espacios de nombres que contienen el tipo de argumento. Por lo tanto, en el código anterior, el compilador encuentra que el objeto
obj
, que es el argumento de la funcióndoSomething()
, pertenece al espacio de nombresMyNamespace
. Entonces, mira ese espacio de nombres para ubicar la declaración dedoSomething()
.¿Cuál es la ventaja de la búsqueda de Koenig?
Como lo demuestra el sencillo ejemplo de código anterior, la búsqueda de Koenig proporciona comodidad y facilidad de uso al programador. Sin la búsqueda de Koenig, habría una sobrecarga en el programador, para especificar repetidamente los nombres completos o, en su lugar, utilizar numerosas
using
declaraciones.¿Por qué la crítica de la búsqueda de Koenig?
La excesiva dependencia de la búsqueda de Koenig puede conducir a problemas semánticos y, a veces, pillar desprevenido al programador.
Considere el ejemplo de
std::swap
, que es un algoritmo de biblioteca estándar para intercambiar dos valores. Con la búsqueda de Koenig, uno debería ser cauteloso al usar este algoritmo porque:puede no mostrar el mismo comportamiento que:
Con ADL, qué versión de la
swap
función se llama dependería del espacio de nombres de los argumentos que se le pasan.Si existe un espacio de nombres
A
yA::obj1
,A::obj2
yA::swap()
existe, el segundo ejemplo dará como resultado una llamada aA::swap()
, que podría no ser lo que el usuario quería.Además, si por alguna razón tanto
A::swap(A::MyClass&, A::MyClass&)
ystd::swap(A::MyClass&, A::MyClass&)
se definen, a continuación, el primer ejemplo llamarástd::swap(A::MyClass&, A::MyClass&)
pero el segundo no se compilará porqueswap(obj1, obj2)
sería ambiguo.Trivialidades:
¿Por qué se llama "búsqueda de Koenig"?
Porque fue ideado por el ex investigador y programador de AT&T y Bell Labs, Andrew Koenig .
Otras lecturas:
Búsqueda del nombre de Herb Sutter en GotW
Estándar C ++ 03/11 [basic.lookup.argdep]: 3.4.2 Búsqueda de nombres dependiente de argumentos.
1 La definición de búsqueda de Koenig es como se define en el libro de Josuttis, The C ++ Standard Library: A Tutorial and Reference .
fuente
std::swap
realidad, tiene que hacer eso, ya que la única alternativa sería agregar unastd::swap
función de plantilla de especialización explícita para suA
clase. Sin embargo, si suA
clase es una plantilla en sí misma, sería una especialización parcial en lugar de una especialización explícita. Y la especialización parcial de la función de plantilla no está permitida. Agregar sobrecarga destd::swap
sería una alternativa, pero está explícitamente prohibido (no puede agregar cosas alstd
espacio de nombres). Entonces ADL es la única forma de hacerlostd::swap
.std::swap()
parece un poco al revés. Esperaría que el problema sea cuandostd::swap()
se selecciona en lugar de la sobrecarga específica para el tipoA::swap()
,. El ejemplo constd::swap(A::MyClass&, A::MyClass&)
parece engañoso. yastd
no tendría una sobrecarga específica para un tipo de usuario, no creo que es un gran ejemplo.MyNamespace::doSomething
, no solo::doSomething
.En Koenig Lookup, si se llama a una función sin especificar su espacio de nombres, entonces el nombre de una función también se busca en los espacios de nombres en los que se define el tipo de argumento (s). Es por eso que también se conoce como Búsqueda de nombre dependiente del argumento , en resumen simplemente ADL .
Es por Koenig Lookup, podemos escribir esto:
De lo contrario, tendríamos que escribir:
lo que realmente es escribir demasiado y el código se ve muy feo!
En otras palabras, en ausencia de Koenig Lookup, incluso un programa Hello World parece complicado.
fuente
std::cout
es un argumento de la función, que es suficiente para habilitar ADL. ¿Lo notaste?ostream<<
(como en lo que toma como argumentos y lo que devuelve). 2) Nombres totalmente calificados (comostd::vector
ostd::operator<<
). 3) Un estudio más detallado de la búsqueda dependiente de argumentos.std::endl
como argumento, en realidad es una función miembro. De todos modos, si uso en"\n"
lugar destd::endl
, entonces mi respuesta es correcta. Gracias por el comentario.f(a,b)
invoca una función libre . Entonces, en el caso destd::operator<<(std::cout, std::endl);
, no existe tal función libre que tomestd::endl
como segundo argumento. Es la función miembro la que tomastd::endl
como argumento y para la que debe escribirstd::cout.operator<<(std::endl);
. y dado que hay una función libre que tomachar const*
como segundo argumento,"\n"
funciona;'\n'
funcionaría tambiénTal vez sea mejor comenzar con el por qué, y solo luego ir al cómo.
Cuando se introdujeron los espacios de nombres, la idea era tener todo definido en los espacios de nombres, para que las bibliotecas separadas no interfieran entre sí. Sin embargo, eso introdujo un problema con los operadores. Mire, por ejemplo, el siguiente código:
Por supuesto, podría haber escrito
N::operator++(x)
, pero eso habría derrotado todo el punto de sobrecarga del operador. Por lo tanto, se tuvo que encontrar una solución que permitiera encontrar el compilador aoperator++(X&)
pesar del hecho de que no estaba dentro del alcance. Por otro lado, todavía no debería encontrar otrooperator++
definido en otro espacio de nombres no relacionado que pueda hacer que la llamada sea ambigua (en este ejemplo simple, no obtendría ambigüedad, pero en ejemplos más complejos, podría). La solución fue la búsqueda dependiente de argumentos (ADL), llamada así ya que la búsqueda depende del argumento (más exactamente, del tipo de argumento). Dado que el esquema fue inventado por Andrew R. Koenig, a menudo también se lo llama búsqueda de Koenig.El truco es que para las llamadas a funciones, además de la búsqueda de nombre normal (que encuentra los nombres en el alcance en el punto de uso), se realiza una segunda búsqueda en los ámbitos de los tipos de cualquier argumento dado a la función. Así, en el ejemplo anterior, si se escribe
x++
en el principal, buscaoperator++
no sólo en el ámbito global, pero, además, en el ámbito en el que el tipo dex
,N::X
, se definió, es decir, ennamespace N
. Y allí encuentra una coincidenciaoperator++
y, porx++
lo tanto, simplemente funciona. Sin embargo, no se encontrará otrooperator++
definido en otro espacio de nombresN2
. Dado que ADL no está restringido a espacios de nombres, también puede usar enf(x)
lugar deN::f(x)
inmain()
.fuente
No todo es bueno, en mi opinión. Las personas, incluidos los vendedores de compiladores, lo han insultado debido a su comportamiento a veces desafortunado.
ADL es responsable de una revisión importante del ciclo for-range en C ++ 11. Para entender por qué ADL a veces puede tener efectos no deseados, considere que no solo se consideran los espacios de nombres donde se definen los argumentos, sino también los argumentos de los argumentos de plantilla de los argumentos, de los tipos de parámetros de los tipos de función / tipos de puntas de los tipos de punteros de esos argumentos , y así sucesivamente.
Un ejemplo usando boost
Esto resultó en una ambigüedad si el usuario usa la biblioteca boost.range, porque ambos
std::begin
se encuentran (mediante ADL usandostd::vector
) yboost::begin
se encuentran (mediante ADL usandoboost::shared_ptr
).fuente
std::begin
borra la ambigüedad del espacio de nombres.