Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
217 views
in Technique[技术] by (71.8m points)

c++ - ostream chaining, output order

I have a function that takes an ostream reference as an argument, writes some data to the stream, and then returns a reference to that same stream, like so:

#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 separate the chaining 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 proper order in the output, but still get a hex value:

Hello, world! How are you?
0x600ec8

I would like to understand what's going on here. Does a normal function take precedence over operator<<, and that's why the output order reverses? What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The behavior of your code is unspecified as per the C++ Standard.

Explanation

The following (I removed std::endl for simplicity)

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

is equivalent to this:

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

which is a function call, passing two arguments:

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

Now, the Standard doesn't specify the order in which arguments are evaluated. It is unspecified. But your compiler seems to evaluate the second argument first, that is why it prints "How are you?" first, evaluating the second argument to a value of type std::ostream& which then gets passed to the call shown above (that value is the object std::cout itself).

Why hexadecimal output?

You get hexadecimal output because the second argument evaluates to std::cout, which is being printed as hexadecimal number, because std::cout implicitly converts into pointer value of void* type, which is why it is printed as hexadecimal number.

Try this:

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 at ideone prints this:

0x804a044
0x804a044 

Also note that I didn't use explicit cast; rather std::cout is implicitly converted into pointer type.

Hope that helps.


What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?

When it depends on what you mean by chaining? Obviously, the following wouldn't work (as explained above):

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

No matter how you write print().

However this is well-defined:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.9k users

...