4

I'm trying to understand the underlying process in C++ that allows us to form the following expression in C++:

cout << "Hello," << "World" << a + b;

From my understanding, first, the insertion operator takes the ostream object cout and the string literal "Hello" as operands and the expression returns a type of cout and thus cout is now the type of the next string literal and finally also the type of the expression a + b.

I'm having trouble understanding the technical details of this process, I understand references are involved which allow us to do this ?

Mutating Algorithm
  • 2,604
  • 2
  • 29
  • 66

3 Answers3

5

You can think of the << operator as being implemented something like this in terms of stdio functions (consider strings only for now):

ostream &operator <<(ostream &stream, const string &data)
{
    fprintf(stream, "%s", data.c_str());
    return stream;
}

This code doesn't work exactly as written because the first argument to fprintf should be a FILE*, not an ostream. But that's not important. The important part relevant to your question is the return stream; at the end, which returns the same stream you passed in back to the caller. With that, you can chain calls together.

The expression

cout << a << b;

is the same as

(cout << a) << b;

The result of (cout << a) is cout again (plus the side effect of actually printing the value of a).

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
5

From my understanding, first, the insertion operator takes the ostream object cout and the string literal "Hello" as operands and the expression returns a type of cout...

Good so far...

and thus cout is now the type of the next string literal and finally also the type of the expression a + b.

I'm not sure what you're trying to say here. Maybe it'll help if the operators are grouped according to precedence:

(((cout << "Hello,") << "World") << (a + b));

The first time operator<< is called, its arguments are cout and "Hello", as you said. That returns cout. Then, the second time, the arguments are cout (the result of the previous one) and "World". Then, the third time, the arguments are cout and the result of a + b.

Maybe it will help further to rewrite the code using the (technically incorrect, see @DavidRodríguez-dribeas's comment) function call syntax:

operator<<(operator<<(operator<<(cout, "Hello,"), "World"), a + b);

Because each time operator<< is called it returns cout, the first argument of each call will be cout.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
1

The shift operators << group left to right. So statement

cout << "Hello," << "World" << a + b;

corresponds to expression

( ( ( cout << "Hello," ) << "World" ) << a + b );

In expression

cout << "Hello,"

there is used overloaded operator function << for left operand of type std::basic_ostream and right operand of type const char *

template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);

It returns reference to basic_ostream. std::cout is defined as an object of type basic_iostream<char>

So after executing

cout << "Hello,"

you get reference to std::cout. which in turn becomes the left operand of expression

cout << "World"

and at last returned reference of the above expression becames the left operand of expression

cout << a + b

where a and b as I suppose are some arithmetic types. This expression is a call of overload operator function for std::basic_ostream and this arithmetic type.

As this operator returns refernce to std_basic_ostream or more precisely to std::cout it becames the return type of the full expression.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335