Бьярн ошибается насчет этого примера ADL, или у меня есть ошибка компилятора?

Я читаю Язык программирования C ++, 4-е издание (от Бьярна Страуструпа) о аргумент-зависимый-поиск. Вот цитата (26.3.6, Сверхагрессивный ADL):

Поиск, зависящий от аргументов (часто называемый ADL), очень полезен, чтобы избежать многословия (14.2.4). Например:

#include <iostream>

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

Без поиска, зависящего от аргументов, манипулятор endl не был бы найден. Как бы то ни было, компилятор замечает, что первым аргументом для << является ostream, определенный в std. Следовательно, он ищет endl в std и находит его (в <iostream>).

А вот результат, созданный компилятором (режим 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;
                                ^

Либо это ошибка в компиляторе, либо в книге. Что говорит стандарт?

Обновление:

Мне нужно немного уточнить. Я знаю, что правильный ответ - использовать std::endl. Вопрос был о тексте в книге. Как уже сказал Лахлан Истон, это не просто опечатка. Весь абзац (вероятно) неверен. Я могу принять такую ​​ошибку, если книга написана другим (менее известным) автором, но у меня были (и до сих пор есть) сомнения, потому что она была написана Бьярном.


person maverik    schedule 06.08.2013    source источник
comment
std::endl без ошибок   -  person aaronman    schedule 06.08.2013
comment
По моему опыту, книги печально известны ошибками и опечатками. Надеюсь, в хорошей книге лишь незначительные / очевидные.   -  person Neil Kirk    schedule 06.08.2013
comment
en.cppreference.com/w/cpp/language/adl   -  person TemplateRex    schedule 07.08.2013
comment
@aaronman OP, очевидно, знает об этом. Из цитаты видно, что Бьярн (создатель C ++) утверждает, что std:: не требуется в этом случае из-за ADL. Но это не компилируется, отсюда и вопрос.   -  person BlueRaja - Danny Pflughoeft    schedule 07.08.2013
comment
@aaronman Я не думаю, что в языке есть что-то еще, что могло бы иметь большее отношение к пространствам имен, чем ADL. Вы случайно не были одним из обозревателей TC ++ PL4?   -  person DanielKO    schedule 07.08.2013
comment
@DanielKO я оговорился, когда сказал, что это не имеет ничего общего с пространствами имен, но вы и сообщения, которые вы дополняете, неверны, ADL влияет на <<, но std::endl является аргументом, и ADL не влияет на него   -  person aaronman    schedule 07.08.2013
comment
Да, дело в том, что в книге прямо не то сказано. Это не опечатка, целый абзац был написан, чтобы описать то, что на самом деле не соответствует действительности. Это ошибка в книге.   -  person DanielKO    schedule 07.08.2013
comment
Как я мог знать, что если у меня нет книги, в любом случае главный ответ не утверждает, что это опечатка   -  person aaronman    schedule 07.08.2013
comment
Похоже, я прокомментировал неправильный ответ.   -  person DanielKO    schedule 07.08.2013
comment
@DanielKO, если вы посмотрите в Интернете, к сожалению для Бьярна, есть много источников, подтверждающих, что это не должно компилироваться, я думаю, что об ошибке, вероятно, следует сообщить Бьярну   -  person aaronman    schedule 07.08.2013
comment
какой-то небрежный Бьярн, чтобы не компилировать свои примеры кода ... UT было бы неплохо, но, вероятно, перебор   -  person NoSenseEtAl    schedule 07.08.2013
comment
@maverik Это ошибка в книге. Я сообщил ему об этой проблеме пару минут назад, дам знать его ответ.   -  person Ali    schedule 07.08.2013
comment
Я все еще не на 100% убежден ни в одной из сторон этого аргумента. Я давно не слежу за C ++, но уверен, что манипуляторы iostream, такие как endl, являются функциями, и, глядя на это, я думаю, что Бьярн может быть прав, а компилятор ошибается (потому что out << endl переводится как endl(out)): cplusplus.com/reference/ostream/endl/?kw=endl   -  person Axel    schedule 07.08.2013
comment
Если вы согласны с Лахланом, сделайте это принятым ответом.   -  person OrangeDog    schedule 07.08.2013
comment
@ BlueRaja-DannyPflughoeft Я понимаю, что это опоздание более чем на неделю, но я имел в виду тот факт, что он спросил, есть ли ошибка в компиляторе   -  person aaronman    schedule 18.08.2013
comment
@ Али, есть новости от Бьярна?   -  person maverik    schedule 21.08.2013
comment
@maverik К сожалению, нет. :( Он может быть в отпуске / слишком занят, чтобы ответить. Попробовать еще раз?   -  person Ali    schedule 21.08.2013
comment
@ Али, нет. Думаю, мы можем подождать еще немного и попробовать еще раз. Спасибо. Дай мне знать, если что-то изменится.   -  person maverik    schedule 22.08.2013
comment
Если вы следите за выступлениями Бьярна (например, на Youtube), он часто цитирует неправильный код или код, поведение которого противоположно тому, на что он указывает. (Беседы в любом случае хороши со многих точек зрения.) Думаю, он человек. @Axel, да, endl - это функция, НО в процитированном выражении endl используется как аргумент для operator<<. Таким образом, правило не применяется, как указывает Питер Александр в своем ответе и в моем комментарии к его ответу.   -  person alfC    schedule 16.12.2013


Ответы (6)


Это не ошибка компилятора. ADL используется для поиска функций, а не аргументов. operator<< - это функция, которую можно найти здесь через ADL, просмотрев параметры std::cout и (что должно быть) std::endl.

person Peter Alexander    schedule 06.08.2013
comment
Фактически, в ретроспективе это вдохновляет способ сделать код действительным, используя тот факт, что std::endl на самом деле (и сбивает с толку) функцию: endl(std::cout << "Hello, world"); // OK because of ADL - person alfC; 16.12.2013

Для тех, кто говорит, что это опечатка, это не так. Либо Бьярн ошибся, либо компилятор ошибся. Параграф после того, что опубликовал OP, гласит

Без поиска, зависящего от аргументов, манипулятор endl не был бы найден. Как бы то ни было, компилятор замечает, что первый аргумент для ‹* - это поток, определенный в std. Следовательно, он ищет endl в std и находит его (in<iostream>).

person Lachlan Easton    schedule 07.08.2013
comment
Вы, сэр, похоже, единственный человек здесь, который действительно прочитал это в книге. Это либо существенное изменение правил языка, делающее все текущие компиляторы C ++ нестандартными (для C ++ 11), либо вопиющая ошибка г-на Страуструпа (а не просто опечатка). Я бы предпочел подождать два дополнительных месяца, чтобы получить исправленное издание. Ему лучше снова отрастить бороду. - person DanielKO; 07.08.2013
comment
Кстати, разметка съела последний бит в цитате, вы, вероятно, захотите использовать обратные кавычки (в <iostream>). - person DanielKO; 07.08.2013

Это опечатка в книге, как уже указывали другие. Однако в книге имеется в виду, что мы должны были бы написать

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

без ADL. Вот что Бьярн имел в виду под многословием.


Я исправился. Как отмечает Лахлан Истон, это не опечатка, а ошибка в книге. У меня нет доступа к этой книге, поэтому я не мог прочитать этот абзац и сам осознать это. Я сообщил об этой ошибке Бьярну, чтобы он исправил ее.


Смешной. Тот же пример есть в Википедии и

Обратите внимание, что std::endl - это функция, но она требует полной квалификации, поскольку используется в качестве аргумента для operator<< (std::endl - указатель на функцию, а не вызов функции).

Несомненно, это ошибка в книге. Тем не менее, пример std::operator<<(std::cout, "Hello, world").operator<<(std::endl); показывает, как ADL помогает уменьшить многословие.


Спасибо gx_ за указывает на мою ошибку.

person Ali    schedule 06.08.2013
comment
Это было больше, чем опечатка, он что-то придумал (как происходит поиск std::operator<<) и написал целый абзац с неверной информацией. Это действительно заставляет вас поверить, что правила ADL изменились и что компиляторы теперь не работают. - person DanielKO; 07.08.2013
comment
на самом деле кажется, что в книге довольно много опечаток, например 17.2.5 - person AndersK; 07.08.2013
comment
@DanielKO Я поправляюсь; Я исправил свой ответ, спасибо. У меня нет доступа к этой книге, поэтому я подумал, что это опечатка. В любом случае ADL действительно помогает уменьшить многословие, и приведенный мной код является примером этого. В любом случае спасибо, что сказали мне. - person Ali; 07.08.2013
comment
На самом деле нам нужно было бы написать std::operator<<(std::cout, "Hello, world").operator<<(std::endl); (см. non-member _2 _ и участник operator<<) - person gx_; 07.10.2013

Подсказка содержится в названии «поиск, зависящий от аргументов».

Это поиск неквалифицированных имен функций, который работает в зависимости от аргументов.

Это не имеет ничего общего с поиском для аргументов.

Бьярн оговорился.

person Lightness Races in Orbit    schedule 06.08.2013

У меня нет книги, но похоже, что это ошибка в книге, тот факт, что в ней отсутствует квалификатор пространства имен, не имеет ничего общего с ADL. Это должно быть std::endl.

person Borgleader    schedule 06.08.2013
comment
Я согласен. Но это довольно странное утверждение (я имею в виду то, что в книге). Надеюсь, Бьярн должен об этом знать. - person maverik; 06.08.2013
comment
@maverik Может быть, он уже это делает, я не удивлюсь, если кто-то уже сообщил об этом. В противном случае можно было бы :) - person Borgleader; 06.08.2013
comment
@maverik это просто опечатка, я думаю, кто-то уже заметил это - person aaronman; 06.08.2013
comment
Да, действительно, я неправильно понял все утверждение (с std::cout). Он говорил о поиске operator<<, а не endl. - person maverik; 06.08.2013

Да, это ошибка - пример неверно сформирован и не должен компилироваться. ADL применяется к неквалифицированным именам функций, которые вводят выражения вызова функций. endl - это id-выражение, пытающееся найти std::endl. endl не вводит выражение вызова функции, поэтому для него не используется поиск, зависящий от аргументов, используется только неквалифицированный поиск, поэтому он не найдет std::endl, как предполагалось.

Более простой и правильный пример:

#include <vector>

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

Таким образом, перед поиском вызова функции (например, f(x,y,z)) с неквалифицированным идентификатором (например, f) сначала анализируются параметры функции (например, x,y,z) для определения их типа. Список связанных пространств имен формируется на основе типов (например, включающее пространство имен определения типа является связанным пространством имен). Затем в этих пространствах имен выполняется дополнительный поиск функции.

Целью примера Бьярна является демонстрация ADL функции std::operator<<, а не std::endl. Это требует дополнительного понимания того, что перегруженные операторы на самом деле являются выражениями вызова функций, поэтому x << y означает operator<<(x,y), а operator<< - неквалифицированное имя, и поэтому к нему применяется ADL. Тип LHS - std::ostream, поэтому std является ассоциированным пространством имен, и поэтому найдено std::operator<<(ostream&, ...).

Исправленный комментарий должен гласить:

Без поиска, зависящего от аргументов, не будет найден перегруженный оператор << в пространстве имен std. Как бы то ни было, компилятор замечает, что первый аргумент для ‹* - это поток, определенный в std. Поэтому он ищет оператор << в std и находит его (в <iostream>).

person Andrew Tomazos    schedule 07.08.2013