Ostream chaining, output order

I have a function that takes an ostream link as an argument, writes some data to a stream, and then returns a link to the same stream, for example:

 #include <iostream> std::ostream& print( std::ostream& os ) { os << " How are you?" << std::endl; return os; } int main() { std::cout << "Hello, world!" << print( std::cout ) << std::endl; } 

The output of this code is:

  How are you? Hello, world!0x601288 

However, if I split the chain of expressions into two statements, like this

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

then I at least get the correct order in the output, but still get the hex value:

 Hello, world! How are you? 0x600ec8 

I would like to understand what is happening here. Does a normal function take precedence over operator<< , and why does the output order change? How can I write a function that inserts data into ostream , but can also be a chain with operator<< ?

+8
c ++ iostream chaining
source share
5 answers

The behavior of your code is not specified according to the C ++ standard.

Description

Next (I removed std::endl for simplicity)

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

equivalent to this:

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

which is a function call, passing two arguments:

  • First argument: operator<<(std::cout, "Hello, World!")
  • Second argument: print(std::cout)

Now the standard does not specify the order in which arguments are evaluated. It is not specified. But your compiler seems to evaluate the second argument first, so it prints "How are you?" first evaluating the second argument to a value of type std::ostream& , which is then passed to the call shown above (this value is the std::cout object itself).

Why is hexadecimal output?

You get hexadecimal output because the second argument evaluates to std::cout , which prints as a hexadecimal number, because std::cout implicitly converted to a pointer value of type void* , so it prints as a hexadecimal number.

Try the following:

 void const *pointer = std::cout; //implicitly converts into pointer type! std::cout << std::cout << std::endl; std::cout << pointer << std::endl; 

It will print the same value for both. For example, this example in ideone prints this:

 0x804a044 0x804a044 

Also note that I did not use explicit casts; rather, std::cout implicitly converted to a pointer type.

Hope this helps.


What is the correct way to write a function that inserts data into a stream, but can also be associated with the <

When does it depend on what you mean by chain? Obviously, the following will not work (as described above):

 std::cout << X << print(std::cout) << Y << Z; //unspecified behaviour! 

No matter how you write print() .

However, this is clearly defined:

 print(std::cout) << X << Y << Z; //well-defined behaviour! 
+5
source share

The reason is that your print () function will evaluate to the rest of the statement and return a reference to cout, which then actually prints as a pointer (cout <cout). This evaluation order is actually undefined behavior, but it seems to apply to your compiler.

As for the definition of a thread-aware “function” that actually defined behavior with the same functionality, this will work;

 #include <iostream> template <class charT, class traits> std::basic_ostream<charT,traits>& print ( std::basic_ostream<charT,traits>& os ) { os << " How are you?" << std::endl; return os; } int main() { std::cout << "Hello, world!" << print << std::endl; } 

See also this answer for more details on what “unspecified” actually means.

+2
source share

In your statement std::cout << "Hello, world!" << print( std::cout ) << std::endl std::cout << "Hello, world!" << print( std::cout ) << std::endl it undefined does std::cout << "Hello, world!" before or after print( std::cout ) . Therefore, the order may not be what you expect.

The value of the hexadecimal value comes from the fact that you also do std::cout << std::cout ( print returns std::cout , which is fed into the << string). The right side of std::cout converted to void * and printed on the output.

+1
source share

This will work to combine print with << and control the order:

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

Or, if you want a function called with << , see Joachim's answer.

+1
source share

Hexadecimal output

Prior to C ++ 11, the std::ostream has a function for converting to void* . Since your print function returns std::ostream& , when evaluating std::cout << print(...) return value of std::ostream l is implicitly converted to void* and then displayed as a pointer value. That is why there is a hexadecimal output.

Since C ++ 11, this conversion function is replaced using the explicit conversion function bool , so trying to output a std::ostream object becomes poorly formed.

Assessment Procedure

Prior to C ++ 17, an overloaded operator is considered a function call to analyze the evaluation order, and the evaluation order of the various arguments to the function call is not specified. Therefore, it is not strange that the print function is first computed, because of which How are you? .

Since C ++ 17, the evaluation order of the operands of the operator << strictly left to right, and the operands of the overloaded operator have the same evaluation order as the boolite input (see more details here ). That way, your program will always get the result (suppose print returns what can be printed)

 Hello, world! How are you? something returned by print 

LIVE EXAMPLE

+1
source share

All Articles