0

From this question & the answers - What is the correct answer for cout << c++ << c;?

I get that

std::cout<<c++<<c;

is evaluated as:

std::operator<<(std::operator<<(std::cout, c++), c);

so the undefined behavior comes from the fact that either of the two parameters could be evaluated first. So far so good.

But why std::operator <<? Why isn't std::ostream::operator << called? And if it is, wouldn't it translate to

(ofstream::operator<<(c++)) << c;
              |
     returns ofstream&

What's the difference between this and method chaining:

struct A
{
    A& foo();
    void goo();
};
//...
A a;
a.foo().goo();

?

Community
  • 1
  • 1
AMCoder
  • 773
  • 1
  • 6
  • 15

1 Answers1

3

std::ostream provides operator<< as overloaded member operators, but other headers (e.g. <string>) provide free operators; so whether << is a member operator or a free function depends on the RHS type.

However, it doesn't matter either way. Let's rename << as foo and cout as bar:

foo(foo(bar, c++), c);
bar.foo(c++).foo(c);

In both cases behaviour is undefined because there is no requirement on the implementation to evaluate the arguments to either call to foo in any particular order. The important consideration is that per Annex C, a chained method call does not constitute more than one full-expression; if the compiler sees

foo.bar(<some-complex-expression>).baz(<another-complex-expression>);

it is free to apply CSE and reordering to the arguments to bar and to baz; indeed examination of side effects may show that the arguments to baz are evaluated before those to bar.

struct A { A &foo(int) { return *this; } };
#include <cstdio>
int main() { A().foo(printf("hello\n")).foo(printf("bye\n")); }

My compiler (gcc 4.1.2) generates a program which prints bye\nhello\n.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • 1
    The first sentence is incorrect, it depends on the [type of argument](http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt) – Jesse Good Jun 29 '12 at 12:54