Surprisingly the below code compiles and runs without error on a variety of compilers and versions.
#include <iostream>
int main() {
endl(std::cout);
return 0;
}
How does it compile? I am sure there is no endl
in global scope because a code like
std::cout << endl;
would fail unless using
is used or else you need std::endl
.
This behavior is called argument dependent lookup or Koenig lookup. This algorithm tells the compiler to not just look at local scope, but also the namespaces that contain the argument's type while looking for unqualified function call.
For ex:
namespace foo {
struct bar{
int a;
};
void baz(struct bar) {
...
}
};
int main() {
foo::bar b = {42};
baz(b); // Also look in foo namespace (foo::baz)
// because type of argument(b) is in namespace foo
}
About the piece of code referred in question text:
endl
or std::endl
is declared in std
namespace as following:
template< class CharT, class Traits >
std::basic_ostream<charT,traits>& endl( std::basic_ostream<CharT, Traits>& os );
or
std::ostream& endl (std::ostream& os);
And cout
or std::cout
is declared as
extern std::ostream cout;
So calling std::endl(std::cout);
is perfectly fine.
Now when one calls just endl(std::cout);
, because the type of argument cout
is from std namespace
, unqualified supposedly a function endl
is searched in std
namespace and it is found succesfully and confirmed to be a function and thus a call to qualified function std::endl
is made.
Further reading: