how does cout << actually work?

C++Cout

C++ Problem Overview


I was wondering how std::cout is able to use << as it does.

My main puzzlement is with whether std::cout as an instance of something. Basically, how is << defined? If I do this for a custom class, I need an instance of some sort...

I could see implementing it as kind of a hack with void pointers or something, but I'd like to see the actual way it's done.

Does anyone here know? Thanks

C++ Solutions


Solution 1 - C++

std::cout is an instance of std::ostream. std::cout << "something" calls one of the operator<< overloads as would be done for any instance of std::ostream.

It's "special" in that it references the console, but otherwise it behaves exactly as an ofstream or an ostringstream would.

EDIT: Chaining works just like it works for any other operators. Consider:

class MyType
{
    friend std::ostream& operator<<(std::ostream& target, const MyType& source);
    int val;
public:
    MyType()
        : val(0)
    { }
    MyType& Add(int toAdd)
    {
        val += toAdd;
        return *this;
    }
};

MyType& operator+(MyType& target, int toAdd)
{
    return target.Add(toAdd);
}

std::ostream& operator<<(std::ostream& target, const MyType& source)
{
    target << source.val;
    return target; //Make chaining work
}

int main()
{
    MyType value1;
    value1 + 2 + 3 + 4;
    std::cout << value1 << " and done!" << std::endl;
}

In this case, the chaining for +s on MyType work for the same reason the <<s work on top of std::ostream. Both + and << are left-associative, which means they're evaluated from left to right. In the case of overloaded operators, the operator is replaced with the equivalent function call.

EDIT2: In a bit more detail:

Let's say you're the compiler and you're parsing

std::cout << value1 << " and done!" << std::endl;

First, << is left associative, so you start on the left. You evaluate the first << and turn it into the function call:

operator<<(std::cout, value1) << " and done!" << std::endl;

You then see that you once again have a std::ostream (the result of the call to operator<<), and a char *, which you once again turn into the function call:

operator<<(operator<<(std::cout, value1)," and done!") << std::endl;

and so on until you've processed the entire statement.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOriView Question on Stackoverflow
Solution 1 - C++Billy ONealView Answer on Stackoverflow