运算符 << 中的执行顺序



我很难理解下面代码中的调用顺序。我期待看到下面的输出

    A1B2

虽然我可以看到我得到的输出是

    BA12

我以为呼叫std::cout<< b->fooA() << b->fooB() << std::endl等同于呼叫

  std::cout.operator<<( b->fooA() ).operator<< ( b->fooB() )

但我可以看到情况并非如此。你能帮助我更好地理解它是如何工作的以及与全球operator<<的关系吗?这是这个序列中最后一个被调用的吗?

#include <iostream>
struct cbase{
    int fooA(){
        std::cout<<"A";
        return 1;
    }
    int fooB(){
        std::cout <<"B";
        return 2;
    }
};
void printcbase(cbase* b ){
    std::cout << b->fooA() << b->fooB() << std::endl;
}
int main(){
    cbase b;
    printcbase( &b );
}
编译器

可以按如下方式计算函数printcbase()

void printcbase(cbase* b ){
    int a = b->FooA();    // line 1
    int b = b->FooB();    // line 2
    std::cout << a;       // line 3
    std::cout << b;       // line 4
    stc::cout << std::endl;
}

或标记为 1 - 4 的许多行的排列中的一些。您只能保证第 1 行在第 3 行之前完成,第 2 行在第 4 行之前完成(当然第 3 行在第 4 行之前(。标准并没有说更多,事实上,您可以使用不同的C++编译器期待不同的结果。

<<

执行顺序定义得很好,但子表达式的计算顺序没有在C++中定义。本文和 C 代码示例说明了您提到的问题。

BA12AB12都是正确的。在下面的代码中:

std::cout<< b->fooA() << b->fooB()

1将出现在2之前,但A可能出现在B之前或之后,因为编译器不承诺它是先计算fooA还是先计算fooB

移位运算符是左关联的; a << b << c读作(a << b) << c,这意味着如果a是具有成员用户定义operator<<的类型(并返回该类型(,则表达式读作a.operator<<(b).operator<<(c)。 如果使用免费operator<<,则读作 operator<<(operator<<(a, b), c)

所以a << b的评估是在(a << b) << c的评估之前排序的,但是bc的评估之间没有排序依赖关系:

a << b << c[1]
|         |
a << b[2] |
|    |    c[5]
a[3] b[4]

如果我们按上述方式对副作用进行编号,则可以将副作用排序为:

54321
53421
45321
43521
43251
35421
34521
34251

自 C++17 起,从 https://en.cppreference.com/w/cpp/language/eval_order

  1. 在移位运算符表达式E1 << E2E1 >> E2中,E1 的每个值计算和副作用都先于每个值计算和 E2 的副作用进行排序

您保证:

std::cout << b->fooA() << b->fooB() << std::endl;
// (((std::cout << b->fooA()) << b->fooB()) << std::endl);

从左到右求值,导致输出A1B2

对于以前的版本,对输出的保证仅为:

  • A 1之前
  • 2B
  • 1 2之前

所以A1B2之一,AB12BA12

相关内容

  • 没有找到相关文章

最新更新