¿Bjarne se equivoca con este ejemplo de ADL o tengo un error del compilador?

81

Estoy leyendo The C ++ Programming Language, 4th Edition (por Bjarne Stroustrup ) sobre. Aquí está la cita (26.3.6, ADL demasiado agresivo):

La búsqueda dependiente de argumentos (a menudo denominada ADL) es muy útil para evitar la verbosidad (14.2.4). Por ejemplo:

#include <iostream>

int main()
{
    std::cout << "Hello, world" << endl; // OK because of ADL
}

Sin la búsqueda dependiente de argumentos, endlno se encontraría el manipulador. Tal como está, el compilador se da cuenta de que el primer argumento de <<está ostreamdefinido en std. Por tanto, busca endlen stdy lo encuentra (en <iostream>).

Y aquí está el resultado producido por el compilador (modo C ++ 11):

prog.cpp: In function ‘int main()’:
prog.cpp:4:36: error: ‘endl’ was not declared in this scope
 std::cout << "Hello, world" << endl;
                                ^

O esto es un error en el compilador o en el libro. ¿Qué dice la norma?

Actualizar:

Necesito aclarar un poco. Sé que la respuesta correcta es usar std::endl. La pregunta era sobre el texto del libro. Como ya dijo Lachlan Easton , no es solo un error tipográfico. Todo el párrafo está (probablemente) mal. Puedo aceptar este tipo de error si el libro es de otro autor (menos conocido), pero tenía (y todavía tengo) dudas porque fue escrito por Bjarne.

maverik
fuente
12
std::endlno bug
Aaronman
3
En mi experiencia, los libros son conocidos por sus errores y errores tipográficos. Con suerte, solo menor / obvio en un buen libro.
Neil Kirk
31
@aaronman OP es obviamente consciente de eso. De la cita, parece que Bjarne (el creador de C ++) afirma que std::no es necesario en este caso, debido a ADL. Pero esto no se compila, de ahí la pregunta.
BlueRaja - Danny Pflughoeft
6
Sí, el punto es que el libro dice explícitamente algo incorrecto. No es un error tipográfico, se escribió un párrafo completo para describir lo que en realidad no es cierto. Es un error en el libro.
DanielKO
7
@maverik Es es un error en el libro. Le informé de este problema hace un par de minutos, les haré saber su respuesta.
Ali

Respuestas:

83

No es un error en el compilador. ADL se utiliza para buscar funciones, no argumentos . operator<<es la función encontrada a través de ADL aquí mirando los parámetros std::couty (lo que debería ser) std::endl.

Peter Alexander
fuente
2
De hecho, en retrospectiva, esto inspira una manera de hacer que el código sea válido explotando el hecho de que std::endles de hecho (y confusamente) una función:endl(std::cout << "Hello, world"); // OK because of ADL
alfC
49

Para aquellos que dicen que es un error tipográfico, no lo es. O Bjarne cometió un error o el compilador lo hizo mal. El párrafo después del publicado por OP dice

Sin una búsqueda dependiente de argumentos, no se encontraría el manipulador endl. Tal como está, el compilador se da cuenta de que el primer argumento de << es un ostream definido en std. Por lo tanto, busca endl en std y lo encuentra (en <iostream>).

Lachlan Easton
fuente
18
Su señor parece ser la única persona aquí que realmente lo leyó en el libro. Es un cambio significativo en las reglas del lenguaje, lo que hace que todos los compiladores de C ++ actuales no sean estándar (para C ++ 11), o un error evidente del Sr. Stroustrup (y no solo un error tipográfico). Preferiría haber esperado dos meses más para obtener una edición revisada. Será mejor que vuelva a dejarse crecer la barba.
DanielKO
Por cierto, el marcado se comió el último bit de la cita, probablemente quieras usar comillas invertidas, "(en <iostream>)".
DanielKO
20

Es un error tipográfico en el libro, como ya han señalado los demás. Sin embargo, lo que se quiere decir en el libro es que tendríamos que escribir

std::operator<<(std::cout, "Hello, world").operator<<(std::endl);

sin ADL. Eso es lo que Bjarne quiso decir con verbosidad.


Me quedo corregido. Como señala Lachlan Easton , no es un error tipográfico, sino un error en el libro. No tengo acceso a este libro, por eso no pude leer ese párrafo y darme cuenta yo mismo. He informado de este error a Bjarne para que pueda corregirlo.


Gracioso. El mismo ejemplo está en Wikipedia y

Tenga en cuenta que std::endles una función pero necesita una calificación completa, ya que se usa como un argumento para operator<<( std::endles un puntero de función, no una llamada a función).

Sin duda, es un error del libro. Sin embargo, el ejemplo std::operator<<(std::cout, "Hello, world").operator<<(std::endl);muestra cómo la ADL ayuda a reducir la verbosidad.


Gracias a gx_ por señalar mi error .

Ali
fuente
Fue más que un error tipográfico, pensó en algo (cómo std::operator<<ocurre la búsqueda ) y escribió un párrafo completo con información incorrecta. Realmente te hace creer que las reglas de ADL cambiaron y que los compiladores ahora no funcionan.
DanielKO
en realidad, parece haber bastantes errores tipográficos en el libro, por ejemplo, 17.2.5
AndersK
@DanielKO Estoy corregido; He arreglado mi respuesta, gracias. No tengo acceso a este libro, por eso pensé que era un error tipográfico. En cualquier caso, ADL ayuda a reducir la verbosidad, y el código que di es un ejemplo de eso. En cualquier caso, gracias por decírmelo.
Ali
En realidad, lo que tendríamos que escribir realmente es std::operator<<(std::cout, "Hello, world").operator<<(std::endl);(ver no miembrooperator<< y miembrooperator<< )
gx_
10

La sugerencia está en el nombre "búsqueda dependiente del argumento".

Es una búsqueda de nombres de funciones no calificados, que funciona según los argumentos .

No tiene nada que ver con la búsqueda de argumentos.

Bjarne se equivocó.

Carreras de ligereza en órbita
fuente
8

No tengo el libro, pero esto parece ser un error en el libro, el hecho de que falte el calificador de espacio de nombres no tiene nada que ver con ADL. Debería serlo std::endl.

Borgleader
fuente
1
Estoy de acuerdo. Pero esta es una declaración bastante extraña (me refiero a la del libro). Espero que Bjarne lo sepa.
maverik
@maverik Quizás ya lo hace, no me sorprendería que alguien ya haya informado de esto. Si no, podría :)
Borgleader
@maverik es solo un error tipográfico en realidad, supongo que alguien más ya lo ha notado
aaronman
2
Sí, realmente, entendí mal toda la declaración (con std::cout) Él estaba hablando de buscar operator<<, no endl.
maverik
4

Sí, es un error: el ejemplo está mal formado y no debería compilarse. ADL se aplica a nombres de funciones no calificados que introducen expresiones de llamada de función. endles una expresión de identificación que intenta buscar std::endl. endlno introduce una expresión de llamada de función, por lo que la búsqueda dependiente de argumentos no se usa para ella, solo se usa una búsqueda no calificada, por lo que no encontrará std::endlcomo se esperaba.

Un ejemplo más simple y correcto sería:

#include <vector>

int main()
{
    std::vector<int> x, y;
    swap(x,y); // calls std::swap due to ADL
}

En resumen, antes de buscar una llamada de función (p f(x,y,z). Ej. ) Con un id no calificado (p f. Ej. ), Primero x,y,zse analizan los parámetros de la función (p . Ej. ) Para determinar su tipo. Se forma una lista de espacios de nombres asociados en función de los tipos (por ejemplo, el espacio de nombres adjunto de la definición del tipo es un espacio de nombres asociado). Estos espacios de nombres se buscan adicionalmente para la función.

La intención del ejemplo de Bjarne es mostrar la ADL de la std::operator<<función, y no std::endl. Esto requiere una comprensión adicional de que los operadores sobrecargados son, de hecho, expresiones de llamada de función, es x << ydecir operator<<(x,y), y operator<<es un nombre no calificado, y por lo tanto ADL se aplica a él. El tipo de la LHS es std::ostreamasí que stdes un espacio de nombres asociado, y por lo tanto std::operator<<(ostream&, ...)se encuentra.

El comentario corregido debe leer:

Sin la búsqueda dependiente del argumento, no se encontraría el <<operador sobrecargado en el stdespacio de nombres. Tal como está, el compilador se da cuenta de que el primer argumento de << es un ostream definido en std. Por lo tanto, busca el operador <<en std y lo encuentra (en <iostream>).

Andrés Tomazos
fuente