运算符<< - 参数评估的顺序

时间:2012-06-29 12:43:51

标签: c++ undefined-behavior

从这个问题&amp;答案 - What is the correct answer for cout << c++ << c;?

我明白了

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

评估为:

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

因此未定义的行为来自于可以首先评估两个参数中的任何一个的事实。到目前为止一切都很好。

但为什么std::operator <<?为什么不调用std::ostream::operator <<?如果是的话,它不会转化为

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

这与方法链接有什么区别:

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

1 个答案:

答案 0 :(得分:3)

std::ostream提供operator<<作为重载成员运算符,但其他标题(例如<string>)提供免费运算符;所以<<是成员运算符还是自由函数取决于RHS类型。

但是,无论哪种方式都没关系。我们将<<重命名为foo,将cout重命名为bar

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

在这两种情况下,行为都是未定义的,因为没有要求实现来评估以任何特定顺序调用foo的参数。重要的考虑因素是,根据附件C,链式方法调用不构成多个完整表达式;如果编译器看到

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

可以自由地应用CSE并重新排序到barbaz的参数;事实上,副作用的检查可能表明baz的论据在bar之前被评估。

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

我的编译器(gcc 4.1.2)生成一个打印bye\nhello\n

的程序