Ist Bjarne in Bezug auf dieses ADL-Beispiel falsch oder habe ich einen Compiler-Fehler?

81

Ich lese The C ++ Programming Language, 4. Ausgabe (von Bjarne Stroustrup ) über. Hier ist das Zitat (26.3.6, Overaggressive ADL):

Die argumentabhängige Suche (oft als ADL bezeichnet) ist sehr nützlich, um Ausführlichkeit zu vermeiden (14.2.4). Beispielsweise:

#include <iostream>

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

Ohne argumentabhängige Suche endlwürde der Manipulator nicht gefunden werden. So wie es ist, bemerkt der Compiler, dass das erste Argument <<ein ostreamdefiniertes in ist std. Daher sucht es endlin stdund findet es (in <iostream>).

Und hier ist das Ergebnis des Compilers (C ++ 11-Modus):

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

Entweder ist dies ein Fehler im Compiler oder im Buch. Was sagt der Standard?

Aktualisieren:

Ich muss ein bisschen klarstellen. Ich weiß, dass die richtige Antwort zu verwenden ist std::endl. Die Frage betraf den Text im Buch. Wie Lachlan Easton bereits sagte, ist es nicht nur ein Tippfehler. Der ganze Absatz ist (wahrscheinlich) falsch. Ich kann diese Art von Fehler akzeptieren, wenn das Buch von einem anderen (weniger bekannten) Autor stammt, aber ich war (und bin) im Zweifel, weil es von Bjarne geschrieben wurde.

maverik
quelle
12
std::endlKein Fehler
Aarononman
3
Nach meiner Erfahrung sind Bücher für Fehler und Tippfehler berüchtigt. Hoffentlich nur geringfügig / offensichtlich in einem guten Buch.
Neil Kirk
31
@aaronman OP ist sich dessen offensichtlich bewusst. Aus dem Zitat geht hervor, dass Bjarne (der Schöpfer von C ++) behauptet, dass std::dies in diesem Fall aufgrund von ADL nicht erforderlich ist. Dies kompiliert aber nicht, daher die Frage.
BlueRaja - Danny Pflughoeft
6
Ja, der Punkt ist, das Buch sagt ausdrücklich das Falsche. Es ist kein Tippfehler, ein ganzer Absatz wurde geschrieben, um zu beschreiben, was eigentlich nicht stimmt. Es ist ein Fehler im Buch.
DanielKO
7
@maverik Es ist ein Fehler im Buch. Ich habe ihm dieses Problem vor ein paar Minuten gemeldet. Ich werde Sie über seine Antwort informieren.
Ali

Antworten:

83

Es ist kein Fehler im Compiler. ADL wird verwendet, um Funktionen und keine Argumente nachzuschlagen . operator<<ist die Funktion, die durch ADL hier durch Betrachten der Parameter std::coutund (was sollte sein) gefunden wird std::endl.

Peter Alexander
quelle
2
Im Nachhinein inspiriert dies einen Weg, den Code gültig zu machen, indem die Tatsache ausgenutzt wird, die std::endltatsächlich (und verwirrend) eine Funktion ist:endl(std::cout << "Hello, world"); // OK because of ADL
alfC
49

Für diejenigen, die sagen, es ist ein Tippfehler, ist es nicht. Entweder hat Bjarne einen Fehler gemacht oder der Compiler hat einen Fehler gemacht. Der Absatz nach dem von OP geposteten lautet

Ohne argumentabhängige Suche würde der Endl-Manipulator nicht gefunden werden. So wie es ist, bemerkt der Compiler, dass das erste Argument für << ein in std definierter ostream ist. Daher sucht es in std nach endl und findet es (in <iostream>).

Lachlan Easton
quelle
18
Ihr Herr scheint die einzige Person hier zu sein, die es tatsächlich in dem Buch gelesen hat. Es handelt sich entweder um eine wesentliche Änderung der Sprachregeln, die dazu führt, dass alle aktuellen C ++ - Compiler nicht mehr dem Standard entsprechen (für C ++ 11), oder um einen offensichtlichen Fehler von Mr. Stroustrup (und nicht nur um einen Tippfehler). Ich hätte lieber zwei zusätzliche Monate gewartet, um eine überarbeitete Ausgabe zu erhalten. Er lässt seinen Bart besser nachwachsen.
DanielKO
Übrigens, das Markup hat das letzte Bit im Zitat gefressen. Sie möchten wahrscheinlich die Backticks "(in <iostream>)" verwenden.
DanielKO
20

Es ist ein Tippfehler im Buch, wie die anderen bereits betont haben. In dem Buch ist jedoch gemeint, dass wir schreiben müssten

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

ohne ADL. Das hat Bjarne mit Ausführlichkeit gemeint.


Ich stehe korrigiert. Wie Lachlan Easton betont, ist es kein Tippfehler, sondern ein Fehler im Buch. Ich habe keinen Zugang zu diesem Buch, deshalb konnte ich diesen Absatz nicht lesen und selbst realisieren. Ich habe Bjarne diesen Fehler gemeldet, damit er ihn korrigieren kann.


Komisch. Das gleiche Beispiel ist auf Wikipedia und

Beachten Sie, dass dies std::endleine Funktion ist, für die jedoch eine vollständige Qualifizierung erforderlich ist, da sie als Argument für verwendet wird operator<<( std::endlist ein Funktionszeiger, kein Funktionsaufruf).

Kein Zweifel, es ist ein Fehler im Buch. Das Beispiel std::operator<<(std::cout, "Hello, world").operator<<(std::endl);zeigt jedoch, wie ADL zur Reduzierung der Ausführlichkeit beiträgt.


Vielen Dank an gx_ für den Hinweis auf meinen Fehler .

Ali
quelle
Es war mehr als ein Tippfehler, er dachte an etwas (wie das Nachschlagen von std::operator<<geschieht) und schrieb einen ganzen Absatz mit falschen Informationen. Es lässt Sie wirklich glauben, dass sich die ADL-Regeln geändert haben und dass die Compiler jetzt kaputt sind.
DanielKO
Tatsächlich scheint es einige Tippfehler in dem Buch zu geben, zB 17.2.5
AndersK
@ DanielKO Ich stehe korrigiert; Ich habe meine Antwort korrigiert, danke. Ich habe keinen Zugang zu diesem Buch, deshalb dachte ich, es sei ein Tippfehler. In jedem Fall hilft ADL bei der Reduzierung der Ausführlichkeit, und der von mir angegebene Code ist ein Beispiel dafür. Auf jeden Fall danke, dass du es mir erzählt hast.
Ali
Eigentlich müssten wir wirklich schreiben std::operator<<(std::cout, "Hello, world").operator<<(std::endl);(siehe Nichtmitgliedoperator<< und Mitgliedoperator<< )
gx_
10

Der Hinweis befindet sich im Namen "argumentabhängige Suche".

Es ist die Suche nach nicht qualifizierten Funktionsnamen, die abhängig von den Argumenten funktioniert .

Es hat nichts mit Lookup zu tun für Argumenten .

Bjarne hat falsch geschrieben.

Leichtigkeitsrennen im Orbit
quelle
8

Ich habe das Buch nicht, aber dies scheint ein Fehler im Buch zu sein. Die Tatsache, dass das Namespace-Qualifikationsmerkmal fehlt, hat nichts mit ADL zu tun. Es sollte sein std::endl.

Borgleader
quelle
1
Genau. Aber das ist eine ziemlich seltsame Aussage (ich meine die im Buch). Ich hoffe, Bjarne sollte davon erfahren.
Maverik
@maverik Vielleicht tut er es schon, ich wäre nicht überrascht, dass jemand dies bereits gemeldet hat. Wenn nicht, könnten Sie :)
Borgleader
@maverik es ist wirklich nur ein Tippfehler, ich würde vermuten, dass jemand anderes es bereits bemerkt hat
Aaronon
2
Ja, wirklich, ich habe die ganze Aussage (mit std::cout) falsch verstanden. Er sprach davon, das zu durchsuchen operator<<, nicht endl.
Maverik
4

Ja, es ist ein Fehler - das Beispiel ist schlecht geformt und sollte nicht kompiliert werden. ADL gilt für nicht qualifizierte Funktionsnamen, die Funktionsaufrufausdrücke einführen. endlist ein ID-Ausdruck, der versucht, nachzuschlagen std::endl. endlführt keinen Funktionsaufrufausdruck ein, sodass für ihn keine argumentabhängige Suche verwendet wird, sondern nur eine nicht qualifizierte Suche, sodass er nicht std::endlwie beabsichtigt gefunden wird.

Ein einfacheres und korrektes Beispiel wäre:

#include <vector>

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

Zusammenfassend lässt sich sagen, bevor ein Funktionsaufruf (z. B. f(x,y,z)) mit einer nicht qualifizierten ID (z. B. f) nachgeschlagen wird, zunächst die Parameter der Funktion (zx,y,z ) analysiert, um ihren Typ zu bestimmen. Eine Liste der zugeordneten Namespaces wird basierend auf den Typen erstellt (z. B. ist der einschließende Namespace der Typdefinition ein zugeordneter Namespace). Diese Namespaces werden dann zusätzlich nach der Funktion durchsucht.

Die Absicht von Bjarnes Beispiel ist es, die ADL der std::operator<<Funktion zu demonstrieren und nicht std::endl. Dies erfordert ein zusätzliches Verständnis, dass überladene Operatoren tatsächlich Funktionsaufrufausdrücke sind, also x << ybedeutet operator<<(x,y)und operator<<ein nicht qualifizierter Name ist, und daher gilt ADL für ihn. Der Typ der LHS ist std::ostreamalso stdein zugeordneter Namespace und wird daher std::operator<<(ostream&, ...)gefunden.

Der korrigierte Kommentar sollte lauten:

Ohne argumentabhängige Suche würde der überladene <<Operator im stdNamespace nicht gefunden. So wie es ist, bemerkt der Compiler, dass das erste Argument für << ein in std definierter ostream ist. Daher sucht es nach dem Operator <<in std und findet ihn (in <iostream>).

Andrew Tomazos
quelle