70

Why do I have to write std::cout and not also std::<< in a line of code like this:

#include <iostream>

int main() {
    std::cout << "Hello, world!";
    return 0;
}

cout comes from std library, and isn't << usually used to do bits shifting? So, why don't I have to write the scope operator :: also before <<, since it is used also with another meaning? How the compiler knows that after std::cout, << means another thing?

7
  • 22
    Argument dependent lookup
    – RiaD
    Commented Oct 1, 2013 at 17:42
  • 5
    This behavior is also known as Koenig lookup or ADL
    – P0W
    Commented Oct 1, 2013 at 17:43
  • 9
    If you were going to fully-qualify the <<, by the way, then it would have to look like std::operator<<(std::cout, "Hello, world!");. The C++ syntax doesn't let you write std::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 are operator<< etc. Commented Oct 1, 2013 at 17:47
  • 9
    +1 for coming up with this. It's not something many people come up with on their own.
    – chris
    Commented Oct 1, 2013 at 17:48
  • 7
    Others have already mentioned argument dependent lookup (aka Koenig lookup). I think it's worth adding that this is precisely the original reason Andrew Koenig invented argument dependent lookup in the first place. It arises in other places, but insertion into (and extraction from) iostreams was what prompted it to start with. Commented Oct 1, 2013 at 17:50

3 Answers 3

55

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
    }
}
3
  • 6
    As a Computer Scientist, this is the correct answer. As an engineer, I have a shorter answer : "By design. Namespaces are designed to require a limited amount of extra qualification. Enough to disambiguate, but not more than that."
    – MSalters
    Commented Oct 1, 2013 at 22:27
  • 1
    BTW, ADL can be disabled by enclosing the function name in parentheses: (find_me)(x). I don't know if/how that works for operator syntax.
    – Matthias
    Commented Oct 9, 2013 at 14:46
  • @Matthias Interesting. For operators, you can either stop unqualified lookup e.g. via a using-declaration (member functions are still found) or you can use the explicit syntax (operator<<)(std::cout, "Hello, world!"). Live example
    – dyp
    Commented Oct 9, 2013 at 16:21
9

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 :)

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.