Является ли Bjarne неправильным в этом примере ADL, или у меня есть ошибка компилятора?

Я читаю Язык программирования С++, 4-е издание (Bjarne Stroustrup) о , Вот цитата (26.3.6, Overaggressive ADL):

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

#include <iostream>

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

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

И вот результат, созданный компилятором (режим С++ 11):

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

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

Update:

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

Ответ 1

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

Ответ 2

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

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

Ответ 3

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

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

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


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


Смешные. Тот же пример находится в Википедии и

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

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


Благодаря gx_ для указав мою ошибку.

Ответ 4

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

Он ищет неквалифицированные имена функций, которые работают в зависимости от аргументов.

Это не имеет никакого отношения к поиску аргументов.

Бьярне оговорок.

Ответ 5

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

Ответ 6

Да, это ошибка - пример плохо сформирован и не должен компилироваться. 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 не будет найден. Как бы то ни было, компилятор замечает, что первый аргумент < < представляет собой ostream, определенный в std. Поэтому он ищет оператор << в std и находит его (в <iostream>).