Чи Б'ярн помиляється щодо цього прикладу ADL, чи у мене є помилка компілятора?


81

Я читаю мову програмування C ++, 4-е видання (автор: Bjarne Stroustrup ). Ось цитата (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. Питання було про текст у книзі. Як уже сказав Лахлан Істон , це не просто друкарська помилка. Весь абзац помилковий (можливо). Я можу прийняти такий тип помилок, якщо книга написана іншим (менш відомим) автором, але я сумнівався (і досі переживаю), оскільки її написав Бьярн.


12
std::endlнемає помилки
aaronman

3
З мого досвіду, книги сумно відомі помилками та помилками. Будемо сподіватися лише незначні / очевидні в хорошій книзі.
Ніл Кірк

31
@aaronman OP це, очевидно, усвідомлює. З цитати видно, що Бьярн (творець C ++) стверджує, що std::в цьому випадку це не потрібно через ADL. Але це не складає, звідси питання.
BlueRaja - Danny Pflughoeft

6
Так, справа в тому, що в книзі прямо сказано не те. Це не друкарська помилка, цілий абзац був написаний для опису того, що насправді не відповідає дійсності. Це помилка в книзі.
DanielKO

7
@maverik Це є помилка в книзі. Я повідомив йому про це питання пару хвилин тому, повідомим вас про його відповідь.
Алі

Відповіді:


83

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


2
Насправді, в ретроспективі це надихає спосіб зробити код дійсним, використовуючи той факт, який std::endlє по суті (і заплутано) функцією:endl(std::cout << "Hello, world"); // OK because of ADL
alfC

49

Для тих, хто каже, що це друкарська помилка, це не так. Або Бьярн помилився, або компілятор помилився. Абзац після розміщеного ОП читає

Без пошуку, залежного від аргументів, маніпулятор endl не був би знайдений. В даний час компілятор зауважує, що першим аргументом << є потік, визначений у std. Тому він шукає endl в std і знаходить його (в <iostream>).


18
Ви, сер, здається, єдина людина, яка насправді читала це в книзі. Це або суттєва зміна мовних правил, що робить усі поточні компілятори C ++ нестандартними (для C ++ 11), або кричуща помилка пана Страуструпа (а не просто друкарська помилка). Я волів би почекати ще два місяці, щоб отримати перероблене видання. Йому краще відростити бороду.
DanielKO

До речі, розмітка з'їла останній біт у цитаті, ви, ймовірно, хочете використовувати зворотні позначки, "(in <iostream>)."
DanielKO

20

Це друкарська помилка в книзі, на що вже вказували інші. Однак у книзі мається на увазі те, що нам довелося б писати

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_ за те, що вказав на мою помилку .


Це було більше, ніж друкарська помилка, він щось продумав (як відбувається пошук std::operator<<) і написав цілий абзац із неправильною інформацією. Це справді змушує вас повірити, що правила ADL змінені, і що компілятори тепер порушені.
DanielKO

насправді, здається, у книзі досить багато помилок, наприклад 17.2.5
AndersK

@DanielKO Я стою виправлений; Я зафіксував свою відповідь, дякую. Я не маю доступу до цієї книги, тому я думав, що це друкарська помилка. У будь-якому випадку ADL допомагає зменшити багатослівність, і приведений мною код є прикладом цього. У будь-якому випадку, дякую, що сказали.
Алі

Насправді те, що нам доведеться писати, насправді є std::operator<<(std::cout, "Hello, world").operator<<(std::endl);(див. Не членoperator<< і членoperator<< )
gx_

10

Підказка міститься в назві "залежний від аргументу пошук".

Це пошук некваліфікованих імен функцій, який працює залежно від аргументів .

Це не має нічого спільного з Lookup для аргументів.

Бжарн помилився.


8

У мене немає книги, але це, здається, помилка в книзі, той факт, що в ній відсутній кваліфікатор простору імен, не має нічого спільного з ADL. Це повинно бути std::endl.


1
Я згоден. Але це досить дивне твердження (я маю на увазі те, що є в книзі). Сподіваюся, Бьярн повинен про це знати.
maverik

@maverik Можливо, він уже це робить, я б не здивувався, що хтось уже повідомив про це. Якщо ні, то можете :)
Borgleader

@maverik це просто друкарська помилка, я гадаю, хтось це вже помітив
aaronman

2
Так, справді, я неправильно зрозумів усі твердження (з std::cout) Він говорив про пошук operator<<, а не endl.
maverik

4

Так, це помилка - приклад неправильно сформований і його не слід компілювати. 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>).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.