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?

4

2 回答 2

13

你是对的,面试官表现出对语言及其规则的普遍缺乏理解,令人恐惧。

这两行是严格等价的,如果operator<<第一行调用的每个函数总是一个自由函数(标准说它们是)。

正如您正确认为的那样,函数调用之间的顺序,除了一个参数是另一个参数的返回值之外,是不确定的(之前或之后,但未指定哪个):

1.9 程序执行[intro.execution]

[...]
15 [...]
调用函数时(无论该函数是否内联),与任何参数表达式或指定被调用函数的后缀表达式相关的每个值计算和副作用都在执行被调用函数体中的每个表达式或语句。[注意:与不同参数表达式相关的值计算和副作用是无序的。—尾注]调用函数(包括其他函数调用)中的每个评估在被调用函数的主体执行之前或之后没有以其他方式明确排序,都是不确定排序的关于被调用函数的执行。9 C++ 中的几个上下文会导致对函数调用进行评估,即使在翻译单元中没有出现相应的函数调用语法。[ 示例:新表达式的求值调用一个或多个分配和构造函数;见 5.3.4。对于另一个示例,转换函数 (12.3.2) 的调用可能出现在没有出现函数调用语法的上下文中。—end example ]被调用函数的执行顺序约束(如上所述)是函数调用的评估特征,无论调用函数的表达式的语法可能是什么。

命名所有部分:

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")

排序约束:

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

或不同的表示:

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

因此,所有有效的完整订单:

abcdef "one\n1\ntwo\n2\n"
abdcef "one\n1two\n\n2\n"
adbcef "one\ntwo\n1\n2\n"
dabcef "two\none\n1\n2\n"
于 2014-08-23T21:19:05.250 回答
6

你是对的,但面试的答案是错误的。

根据 C++11 标准的第 1.9/15 段:

除非另有说明,对单个运算符的操作数和单个表达式的子表达式的求值是无序的。

例如,这是 Clang 3.4 产生的:

one
1
two
2
于 2014-08-23T20:55:55.067 回答