81

I'm reading The C++ Programming Language, 4th Edition (by Bjarne Stroustrup) about . Here is the quote (26.3.6, Overaggressive ADL):

Argument-dependent lookup (often referred to as ADL) is very useful to avoid verbosity (14.2.4). For example:

#include <iostream>

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

Without argument-dependent lookup, the endl manipulator would not be found. As it is, the compiler notices that the first argument to << is an ostream defined in std. Therefore, it looks for endl in std and finds it (in <iostream>).

And here's the result produced by the compiler (C++11 mode):

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

Either this is a bug in the compiler or in the book. What does the standard say?

Update:

I need to clarify a bit. I know that the right answer is to use std::endl. The question was about the text in the book. As Lachlan Easton already said, it is not just a typo. The whole paragraph is (probably) wrong. I can accept this kind of error if the book is by an other (lesser known) author, but I was (and still am) in doubt because it was written by Bjarne.

Community
  • 1
  • 1
maverik
  • 5,508
  • 3
  • 35
  • 55
  • 12
    `std::endl` no bug – aaronman Aug 06 '13 at 17:09
  • 3
    In my experience, books are notorious for bugs and typos. Hopefully only minor/obvious in a good book. – Neil Kirk Aug 06 '13 at 17:14
  • http://en.cppreference.com/w/cpp/language/adl – TemplateRex Aug 06 '13 at 20:09
  • 32
    @aaronman OP is obviously aware of that. From the quote, it appears that Bjarne *(the creator of C++)* is claiming that the `std::` is not required in this case, due to ADL. But this does not compile, hence the question. – BlueRaja - Danny Pflughoeft Aug 06 '13 at 22:17
  • @aaronman I don't think there's anything else in the language that could have **more** to do with namespaces than ADL. Were you one of TC++PL4's reviewers by any chance? – DanielKO Aug 07 '13 at 04:25
  • @DanielKO i misspoke when I said it has nothing to do with namespaces, but you and the posts your are complementing are wrong, ADL has an effect on the `<<`, but `std::endl` is an argument and ADL does not take effect on it – aaronman Aug 07 '13 at 04:33
  • 6
    Yes, the point is, the book explicitly says the wrong thing. It's not a typo, a whole paragraph was written to describe what isn't actually true. It's a bug in the book. – DanielKO Aug 07 '13 at 04:43
  • How could I know that if I don't have the book, anyway the top answer doesn't claim that it is a typo – aaronman Aug 07 '13 at 04:45
  • Looks like I commented on the wrong answer. – DanielKO Aug 07 '13 at 04:48
  • @DanielKO if you look around the internet, unfortunately for Bjarne, there are many sources that confirm this should not compile, I think the error should probably be reported to Bjarne – aaronman Aug 07 '13 at 04:52
  • 2
    kind of sloppy of Bjarne not to compile his code examples... UT would be nice but probably overkill – NoSenseEtAl Aug 07 '13 at 07:18
  • 7
    @maverik It *is* an error in the book. I reported this issue to him a couple of minutes ago, I will let you know about his answer. – Ali Aug 07 '13 at 09:57
  • 3
    I'm still not 100% convinced by either side of the argument. I haven't been following C++ for quite a while, but I'm sure iostream manipulators such as `endl` are functions, and looking at this, I think Bjarne might be right and the compiler wrong (because `out << endl` translates to `endl(out)`): http://www.cplusplus.com/reference/ostream/endl/?kw=endl – Axel Aug 07 '13 at 11:30
  • 2
    If you agree with Lachlan, make that the accepted answer. – OrangeDog Aug 07 '13 at 13:06
  • @BlueRaja-DannyPflughoeft I realize this is over a week late but I was referring to the fact that he asked if there was a bug in the compiler – aaronman Aug 17 '13 at 23:43
  • @Ali, any news from Bjarne? – maverik Aug 21 '13 at 18:41
  • 1
    @maverik Unfortunately no. :( He might be on vacation / too busy to answer. Shall I try it again? – Ali Aug 21 '13 at 18:47
  • @Ali, nope. I think we can wait a little bit more and then try again. Thanks. Let me know if something will change. – maverik Aug 21 '13 at 20:14
  • 2
    If you follow Bjarne talks (like in Youtube) he often quotes incorrect code, or code that has the opposite behavior to what he points out. (The talks are good anyways from many points of view.) He is human I guess. @Axel, yes `endl` is a function BUT in the expression cited `endl` is used as **argument** of `operator<<`. So the rule doesn't apply as Peter Alexander points out in his answer and my comment to his answer. – alfC Dec 16 '13 at 06:23

6 Answers6

83

It's not a bug in the compiler. ADL is used to lookup functions not arguments. operator<< is the function found through ADL here by looking at the parameters std::cout and (what should be) std::endl.

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
  • 2
    In fact, in retrospect this inspires a way to make the code valid by exploiting the fact that `std::endl` is as a matter of fact (and confusingly) a function: `endl(std::cout << "Hello, world"); // OK because of ADL` – alfC Dec 16 '13 at 06:24
  • Stumbling over here a decade too late I'm wondering why no one had the idea to resolve `out << std::endl` vs. `std::endl(out)` – pretty simple, the operator must look somehow like `std::ostream& operator<<(std::ostream& s, whatever_type_of_endl e) { e(s); return s; }`... – Aconcagua Apr 13 '23 at 11:31
49

For those saying it's a typo, it's not. Either Bjarne made a mistake or the compiler has it wrong. The paragraph after the one posted by OP reads

Without argument-dependent lookup, the endl manipulator would not be found. As it is, the compiler notices that the first argument to << is an ostream defined in std. Therefore, it looks for endl in std and finds it (in<iostream>).

Lachlan Easton
  • 741
  • 5
  • 10
  • 18
    You sir appears to be the only person here that actually read it on the book. It's either a significant change in the language rules, making all current C++ compilers non-standard (for C++11), or a glaring error from Mr. Stroustrup (and not just a typo). I'd rather have waited two extra months to get a revised edition. He better grow his beard back. – DanielKO Aug 07 '13 at 04:20
  • By the way, the markup ate the last bit in the quote, you probably want to use backticks, "(in ``)." – DanielKO Aug 07 '13 at 04:46
20

It is a typo in the book as the others have already pointed out. However, what is meant in the book is that we would have to write

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

without ADL. That's what Bjarne meant by verbosity.


I stand corrected. As Lachlan Easton points out, it isn't a typo but a mistake in the book. I don't have access to this book that's why I couldn't read that paragraph and realize it myself. I have reported this mistake to Bjarne so that he can correct it.


Funny. The same example is on Wikipedia and

Note that std::endl is a function but it needs full qualification, since it is used as an argument to operator<< (std::endl is a function pointer, not a function call).

No doubt, it is a mistake in the book. Nevertheless the example std::operator<<(std::cout, "Hello, world").operator<<(std::endl); shows how ADL helps reducing the verbosity.


Thanks to gx_ for pointing out my mistake.

Community
  • 1
  • 1
Ali
  • 56,466
  • 29
  • 168
  • 265
  • It was more than a typo, he thought of something (how the lookup of `std::operator<<` happens) and wrote an entire paragraph with incorrect information. It really makes you believe ADL rules changed and that the compilers are now broken. – DanielKO Aug 07 '13 at 04:51
  • actually there seems to be quite a few typos in the book e.g. 17.2.5 – AndersK Aug 07 '13 at 05:09
  • @DanielKO I stand corrected; I have fixed my answer, thanks. I don't have access to this book that's why I thought it was a typo. In any case, ADL does help in reducing verbosity, and the code I gave is an example of that. In any case, thanks for telling me. – Ali Aug 07 '13 at 09:12
  • Actually what we would have to write really is `std::operator<<(std::cout, "Hello, world").operator<<(std::endl);` (see [non-member `operator<<`](http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2) and [member `operator<<`](http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt)) – gx_ Oct 07 '13 at 16:20
10

The hint is in the name "argument-dependent lookup".

It's lookup for unqualified function names, that works depending on the arguments.

It's got nothing to do with lookup for arguments.

Bjarne misspoke.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
8

I don't have the book, but this seems to be an error in the book, the fact that it's missing the namespace qualifier has nothing to do with ADL. It should be std::endl.

Borgleader
  • 15,826
  • 5
  • 46
  • 62
  • 1
    I agree. But this is rather strange statement (I mean the one in the book). I hope Bjarne should know about it. – maverik Aug 06 '13 at 17:12
  • @maverik Maybe he already does, I wouldn't be surprised that someone already reported this. If not, you could :) – Borgleader Aug 06 '13 at 17:13
  • @maverik it's just a typo really, I would guess someone else has already noticed it – aaronman Aug 06 '13 at 17:13
  • 2
    Yep, really, I misunderstood all the statement (with `std::cout`) He was talking about searching the `operator<<`, not `endl`. – maverik Aug 06 '13 at 17:16
4

Yes, it is an error - the example is ill-formed and should not compile. ADL applies to unqualified function names that introduce function call expressions. endl is an id-expression attempting to lookup std::endl. endl does not introduce a function call expression so argument-dependent lookup is not used for it, only unqualified lookup is used, so it will not find std::endl as intended.

A simpler and correct example would be:

#include <vector>

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

In summary, before a function call (eg f(x,y,z)) with an unqualified id (eg f) is looked up, first the parameters of the function (eg x,y,z) are analyzed to determine their type. A list of associated namespaces is formed based on the types (for example the enclosing namespace of the type's definition is an associated namespace). These namespaces are then additionally searched for the function.

The intention of Bjarne's example is to show off the ADL of the std::operator<< function, and not std::endl. This requires an additional understanding that overloaded operators are in fact function call expressions, so x << y means operator<<(x,y), and operator<< is an unqualified name, and therefore ADL applies to it. The type of the LHS is std::ostream so std is an associated namespace, and therefore std::operator<<(ostream&, ...) is found.

The corrected comentary should read:

Without argument-dependent lookup, the overloaded << operator in the std namespace would not be found. As it is, the compiler notices that the first argument to << is an ostream defined in std. Therefore, it looks for the operator << in std and finds it (in <iostream>).

Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319