Why I have to write std::cout and not also std::<<

Solution 1:

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
    }
}

Solution 2:

In std::cout << "Hello, world!"; //calls std:::operator <<

This is achieved with Argument-dependent name lookup (ADL, aka Koenig Lookup)

Although we have only one std qualifier but there are two things that comes up from std namespace

  • cout
  • <<

Without ADL, (Koenig Lookup)

std::cout std:: << "Hello World" ;//this won't compile

In order to compile it, we need to use it more uglier form

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

So to avoid such ugly syntax we must appreciate Koenig Lookup :)

Solution 3:

The compiler sees that the arguments to << are an std::ostream object and a string, and so is able to locate the proper operator<< definition based on this.

You can sort of think of the argument types of an operator (or really, any function) as part of its name.