Reputation: 5606
I'm reading The C++ Programming Language, 4th Edition (by Bjarne Stroustrup) about argument-dependent-lookup. 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 anostream
defined instd
. Therefore, it looks forendl
instd
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.
Upvotes: 81
Views: 3649
Reputation: 68738
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 thestd
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>
).
Upvotes: 4
Reputation: 58511
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 tooperator<<
(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.
Upvotes: 20
Reputation: 741
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>
).
Upvotes: 49
Reputation: 385405
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.
Upvotes: 10
Reputation: 54300
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
.
Upvotes: 83
Reputation: 15916
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
.
Upvotes: 8