11

Suppose following piece of code:

#include <iostream>
using namespace std;

char one()
{
    cout << "one\n";
    return '1';
}

char two()
{
    cout << "two\n";
    return '2';
}

int main(int,char**)
{
    // 1:
    cout << one()
         << '\n'
         << two()
         << '\n';

    // 2:
    operator<<(
        operator<<(
            operator<<(
                operator<<(
                    cout, 
                    one()),
                '\n'),
            two()),
        '\n');
}

execution of lines marked as 1 and 2, being compiled with ideone does the same, it prints following:

two
one
1
2

From my point of view, what we observe here is unspecified behaviour, as order in which function arguments are resolved is unspecified.

This was a question at an interview, printing above given sequence (without any alternatives) was supposed to be correct answer, but is it really correct?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
sukhmel
  • 1,402
  • 16
  • 29

2 Answers2

13

You are correct, and the interviewer shows a frighteningly common lack of understanding about the language and its rules.

Those two lines are strictly equivalent, iff every operator<< called for the first line is always a free function (The standard says they are).

As you rightly thought, the ordering between the function-calls, except where ones arguments are the return-value of another, are indeterminately sequenced (before or after, but unspecified which):

1.9 Program execution [intro.execution]

[...]
15 [...]
When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. [ Note: Value computations and side effects associated with different argument expressions are unsequenced. —end note ] Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.9 Several contexts in C++ cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit. [ Example: Evaluation of a new expression invokes one or more allocation and constructor functions; see 5.3.4. For another example, invocation of a conversion function (12.3.2) can arise in contexts in which no function call syntax appears. —end example ] The sequencing constraints on the execution of the called function (as described above) are features of the function calls as evaluated, whatever the syntax of the expression that calls the function might be.

Naming all the parts:

cout << one() // a) execute one()           ("one\n")
              // b) output the return-value ("1")
     << '\n'  // c) output newline          ("\n")
     << two() // d) execute two()           ("two\n")
              // e) output the return-value ("2")
     << '\n'; // f) output newline          ("\n")

Ordering constraints:

a < b < c < e < f
d < e < f

Or a different representation:

a < b < c <
          < e < f
d         <

Thus, all valid full orders:

abcdef "one\n1\ntwo\n2\n"
abdcef "one\n1two\n\n2\n"
adbcef "one\ntwo\n1\n2\n"
dabcef "two\none\n1\n2\n"
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • Thanks for very thorough explanation. Although it seems, you have a small mistake in ordering constraints: `d` should be in same column as `a`, if I got it correct. Besides, it has not appearing to me, that `"one\n1\ntwo\n2\n"` and `"one\n1two\n\n2\n"` were also possible (probably, because I have not written down constraints as you did). – sukhmel Aug 23 '14 at 22:43
  • the column does not really matter, though I've now put it at the front of its line anyway. – Deduplicator Aug 23 '14 at 22:44
  • 1
    ah, now I got it, that `d` and all of (`a`,`b`,`c`) are unsequenced, and `d` may appear at any time before `e`, but not simultaneously with others. – sukhmel Aug 23 '14 at 22:52
  • Speaking of lack of understanding, it took me two days of being disturbed by this to grasp the mechanics, although my knowledge was enough to understand. There is still a long path ahead of me. – sukhmel Aug 23 '14 at 22:55
6

You are correct, but the interview answer is wrong.

Per Paragraph §1.9/15 of the C++11 Standard:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

As an example, this is what Clang 3.4 produces:

one
1
two
2
David G
  • 94,763
  • 41
  • 167
  • 253
  • Sorry, I will rephrase to be more precise. Please edit the answer to comply the edit, and I will accept it, as it points at part of standard I needed. – sukhmel Aug 23 '14 at 20:56
  • @sukhmel Your suspicion was correct. The interview answer is wrong. The order of evaluation is indeed unsequenced. – David G Aug 23 '14 at 21:00
  • 1
    Note however that `one()` and `two()`, being function calls, will be indeterminately sequenced (i.e., their execution can't overlap). – T.C. Aug 23 '14 at 21:02
  • 1
    As I am digging deeper into c++, it appears to me, that a lot of tests and interview questions are relying on undefined or unspecified behaviour, platform-dependent things, and so on. Makes me sad a little. – sukhmel Aug 23 '14 at 21:03
  • @T.C. yeah, that was clear to me while I was investigating, but thanks for pointing out. – sukhmel Aug 23 '14 at 21:04
  • 1
    @sukhmel Those interview questions might have been influenced by their behavior in other languages where the order of evaluation well-defined (like Java). – David G Aug 23 '14 at 21:04