Czy Bjarne myli się co do tego przykładu ADL, czy mam błąd kompilatora?

81

Czytam The C ++ Programming Language, 4th Edition (by Bjarne Stroustrup ) o. Oto cytat (26.3.6, Overaggressive ADL):

Wyszukiwanie zależne od argumentów (często nazywane ADL) jest bardzo przydatne w celu uniknięcia gadatliwości (14.2.4). Na przykład:

#include <iostream>

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

Bez wyszukiwania zależnego od argumentów endlmanipulator nie zostałby znaleziony. W obecnej sytuacji kompilator zauważa, że ​​pierwszy argument do <<jest ostreamzdefiniowany w std. Dlatego szuka endlw stdi znajduje to (w <iostream>).

A oto wynik wygenerowany przez kompilator (tryb 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;
                                ^

Albo jest to błąd w kompilatorze, albo w książce. Co mówi norma?

Aktualizacja:

Muszę trochę wyjaśnić. Wiem, że właściwą odpowiedzią jest użycie std::endl. Pytanie dotyczyło tekstu w książce. Jak już powiedział Lachlan Easton , nie jest to zwykła literówka. Cały akapit jest (prawdopodobnie) błędny. Mogę zaakceptować tego rodzaju błąd, jeśli książka pochodzi od innego (mniej znanego) autora, ale miałem (i nadal mam) wątpliwości, ponieważ została napisana przez Bjarne'a.

maverik
źródło
12
std::endlbez błędu
aaronman
3
Z mojego doświadczenia wynika, że ​​książki są znane z błędów i literówek. Mam nadzieję, że w dobrej książce tylko drobne / oczywiste.
Neil Kirk
31
@aaronman OP jest tego oczywiście świadomy. Z cytatu wynika, że ​​Bjarne (twórca C ++) twierdzi, że std::nie jest to wymagane w tym przypadku ze względu na ADL. Ale to się nie kompiluje, stąd pytanie.
BlueRaja - Danny Pflughoeft
6
Tak, chodzi o to, że książka wyraźnie mówi coś niewłaściwego. To nie jest literówka, napisano cały akapit, aby opisać, co w rzeczywistości nie jest prawdą. To błąd w książce.
DanielKO,
7
@maverik To jest błąd w książce. Zgłosiłem mu ten problem kilka minut temu, powiem ci o jego odpowiedzi.
Ali

Odpowiedzi:

83

To nie jest błąd w kompilatorze. ADL służy do wyszukiwania funkcji, a nie argumentów . operator<<to funkcja znaleziona tutaj przez ADL, patrząc na parametry std::couti (co powinno być) std::endl.

Peter Alexander
źródło
2
W rzeczywistości, z perspektywy czasu, inspiruje to sposób, aby kod był ważny, wykorzystując fakt, że std::endljest on w rzeczywistości (i endl(std::cout << "Hello, world"); // OK because of ADL
myląco
49

Dla tych, którzy mówią, że to literówka, tak nie jest. Albo Bjarne popełnił błąd, albo kompilator pomylił się. Brzmi akapit po opublikowanym przez OP

Bez wyszukiwania zależnego od argumentów manipulator endl nie zostałby znaleziony. W obecnej sytuacji kompilator zauważa, że ​​pierwszym argumentem << jest ostream zdefiniowany w std. Dlatego szuka endl w std i znajduje go (in <iostream>).

Lachlan Easton
źródło
18
Pan wydaje się być jedyną osobą, która przeczytała to w książce. Jest to albo znacząca zmiana w zasadach języka, która sprawia, że ​​wszystkie obecne kompilatory C ++ są niestandardowe (dla C ++ 11), albo rażący błąd pana Stroustrupa (i nie tylko literówka). Wolałbym poczekać dwa dodatkowe miesiące na wydanie poprawionej wersji. Lepiej zapuści brodę.
DanielKO,
Nawiasem mówiąc, znaczniki zjadły ostatni fragment cytatu, prawdopodobnie chcesz użyć znaku odwrotnego „(in <iostream>)”.
DanielKO,
20

Jest to literówka w książce, jak inni już zauważyli. Jednak w książce chodzi o to, że musielibyśmy pisać

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

bez ADL. To właśnie miał na myśli Bjarne przez gadatliwość.


Poprawiono mnie. Jak podkreśla Lachlan Easton , nie jest to literówka, ale błąd w książce. Nie mam dostępu do tej książki, dlatego nie mogłem przeczytać tego akapitu i sam tego zrealizować. Zgłosiłem ten błąd Bjarne'owi, aby mógł go poprawić.


Zabawny. Ten sam przykład jest na Wikipedii i

Zauważ, że std::endljest to funkcja, ale wymaga pełnej kwalifikacji, ponieważ jest używana jako argument operator<<( std::endljest wskaźnikiem funkcji, a nie wywołaniem funkcji).

Bez wątpienia to błąd w książce. Niemniej jednak przykład std::operator<<(std::cout, "Hello, world").operator<<(std::endl);pokazuje, jak ADL pomaga zredukować gadatliwość.


Dziękuję gx_ za wskazanie mojego błędu .

Ali
źródło
To było więcej niż literówka, pomyślał o czymś (jak std::operator<<dzieje się wyszukiwanie ) i napisał cały akapit z nieprawidłowymi informacjami. To naprawdę sprawia, że ​​wierzysz, że reguły ADL uległy zmianie i że kompilatory są teraz zepsute.
DanielKO,
wydaje się, że w książce jest sporo literówek, np. 17.2.5
AndersK
@DanielKO Stoję poprawione; Naprawiłem odpowiedź, dzięki. Nie mam dostępu do tej książki, dlatego pomyślałem, że to literówka. W każdym razie ADL pomaga w zmniejszaniu gadatliwości, a kod, który podałem, jest tego przykładem. W każdym razie, dziękuję za informację.
Ali
Właściwie to, co naprawdę musielibyśmy napisać, to std::operator<<(std::cout, "Hello, world").operator<<(std::endl);(zobacz osoby niebędące członkamioperator<< i członkamioperator<< )
gx_
10

Wskazówka jest w nazwie "wyszukiwanie zależne od argumentów".

Jest to wyszukiwanie niekwalifikowanych nazw funkcji, które działa w zależności od argumentów .

To nie ma nic wspólnego z odnośnika do argumenty.

Bjarne źle powiedział.

Lekkość wyścigów na orbicie
źródło
8

Nie mam książki, ale wydaje się, że jest to błąd w książce, fakt, że brakuje w niej kwalifikatora przestrzeni nazw, nie ma nic wspólnego z ADL. Tak powinno być std::endl.

Borgleader
źródło
1
Zgadzam się. Ale to dość dziwne stwierdzenie (mam na myśli to w książce). Mam nadzieję, że Bjarne powinien o tym wiedzieć.
maverik
@maverik Może już to robi, nie zdziwiłbym się, że ktoś już to zgłosił. Jeśli nie, możesz :)
Borgleader
@maverik to naprawdę tylko literówka, myślę, że ktoś już to zauważył
aaronman
2
Tak, naprawdę źle zrozumiałem całe stwierdzenie (z std::cout). Mówił o wyszukiwaniu operator<<, a nie endl.
maverik
4

Tak, to błąd - przykład jest źle sformułowany i nie powinien się kompilować. ADL ma zastosowanie do niekwalifikowanych nazw funkcji, które wprowadzają wyrażenia wywołania funkcji. endljest wyrażeniem id próbującym wyszukać std::endl. endlnie wprowadza wyrażenia wywołania funkcji, więc nie jest do niego używane wyszukiwanie zależne od argumentów, używane jest tylko wyszukiwanie niekwalifikowane, więc nie zostanie znalezione std::endlzgodnie z przeznaczeniem.

Prostszy i poprawny przykład to:

#include <vector>

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

Podsumowując, zanim wywołanie funkcji (np. f(x,y,z)) Z niekwalifikowanym identyfikatorem (np. f) Zostanie wyszukane, najpierw parametry funkcji (np.x,y,z analizowane są ) W celu określenia ich typu. Lista powiązanych przestrzeni nazw jest tworzona na podstawie typów (na przykład obejmująca przestrzeń nazw definicji typu jest skojarzoną przestrzenią nazw). Te przestrzenie nazw są następnie dodatkowo przeszukiwane pod kątem funkcji.

Celem przykładu Bjarne'a jest pokazanie ADL std::operator<<funkcji, a nie std::endl. Wymaga to dodatkowego zrozumienia, że ​​przeciążone operatory są w rzeczywistości wyrażeniami wywołania funkcji, a więc x << yoznacza operator<<(x,y)i operator<<jest nazwą niekwalifikowaną, a zatem ADL ma do niej zastosowanie. Typ LHS jest std::ostreamwięc stdskojarzoną przestrzenią nazw i dlatego std::operator<<(ostream&, ...)został znaleziony.

Poprawiony komentarz powinien brzmieć:

Bez wyszukiwania zależnego od argumentów nie zostałby znaleziony przeciążony <<operator w stdprzestrzeni nazw. W obecnej sytuacji kompilator zauważa, że ​​pierwszym argumentem << jest ostream zdefiniowany w std. Dlatego szuka operatora <<w std i znajduje go (w <iostream>).

Andrew Tomazos
źródło