First, the compiler will look at the types to the left and right of <<
. std::cout
is of type std::ostream
, the string literal is of type array of 15 const char
. As the left is of class type, it will search for a function named operator<<
. The question is, where will it look?
The lookup for this name operator<<
is a so-called unqualified lookup, because the function name isn't qualified like std::operator<<
. Unqualified lookup for function names invokes argument-dependent lookup. The argument-dependent lookup will search in the classes and namespaces associated with the argument types.
When you include <iostream>
, a free function of the signature
template<typename traits>
std::basic_ostream<char, traits>& operator<<(std::basic_ostream<char, traits>&,
const char*);
has been declared in namespace std
. This namespace is associated with the type of std::cout
, therefore this function will be found.
std::ostream
is just a typedef for std::basic_ostream<char, std::char_traits<char>>
, and the array of 15 const char
can be converted implicitly to a char const*
(pointing to the first element of the array). Therefore, this function can be called with the two argument types.
There are other overloads of operator<<
, but the function I mentioned above is the best match for the argument types and the one selected in this case.
A simple example of argument-dependent lookup:
namespace my_namespace
{
struct X {};
void find_me(X) {}
}
int main()
{
my_namespace::X x;
find_me(x); // finds my_namespace::find_me because of the argument type
}
N.B. As this function is a operator, the actual lookup is a bit more complex. It is looked up via qualified lookup in the scope of the first argument (if that's of class type), i.e. as a member function. Additionally, unqualified lookup is performed, but ignoring all member functions. The result is slightly different, because unqualified lookup is actually like a two-step procedure, where argument-dependent lookup is the second step. If the first step finds a member function, the second step is not performed, i.e. argument-dependent lookup is not used.
Compare:
namespace my_namespace
{
struct X
{
void find_me(X, int) {}
void search();
};
void find_me(X, double) {}
void X::search() {
find_me(*this, 2.5); // only finds X::find_me(int)
// pure unqualified lookup (1st step) finds the member function
// argument-dependent lookup is not performed
}
}
to:
namespace my_namespace
{
struct X
{
void operator<<(int) {}
void search();
};
void operator<<(X, double) {}
void X::search() {
*this << 2.5; // find both because both steps are always performed
// and overload resolution selects the free function
}
}
<<
, by the way, then it would have to look likestd::operator<<(std::cout, "Hello, world!");
. The C++ syntax doesn't let you writestd::cout std::<< "Hello, world!"
to mean the same thing because the notion of namespaces doesn't apply to the operators themselves, it applies to the names of the functions that overload them, which areoperator<<
etc.