编译器是否允许在不同的函数参数中交织子表达式的评估?

时间:2016-08-30 23:10:31

标签: c++

我想知道以下情况:

void f(int a, int b) { }

int a(int x) { std::cout << "func a" << std::endl; return 1; }
int b(int x) { std::cout << "func b" << std::endl; return 2; }

int x() { std::cout << "func x" << std::endl; return 3; }
int y() { std::cout << "func y" << std::endl; return 4; }

f(a(x()), b(y()));

阅读http://en.cppreference.com/w/cpp/language/eval_order后,我仍然难以理解以下评估顺序是否可行:

x() - &gt; y() - &gt; a() - &gt; b()

或标准保证a(x())b(y())将被评估为单位,可以这么说。

换句话说,是否有可能打印

func x
func y
func a
func b

在GCC 5.4.0上运行此测试让我觉得更合乎逻辑

func y
func b
func x
func a

但这当然没有告诉我标准要求的内容。获得对标准的引用会很好。

2 个答案:

答案 0 :(得分:14)

在C ++ 14及更早版本中,x -> y -> a -> b是可能的。这里的排序关系是:

  • 在致电x之前,对a的来电已排序。
  • 在致电y之前,对b的来电已排序。
  • 在致电a之前,对f的来电已排序。
  • 在致电b之前,对f的来电已排序。

订单没有其他限制。如果你想强制执行某些特定的排序,那么你必须将这个调用分解为多个完整表达式。

在C ++ 14标准中,注意事项[expr.call] / 8澄清了这一意图:

  

[注意:后缀表达式和参数的评估都是相对于彼此无法排序的。在输入函数之前,对参数评估的所有副作用进行排序。 - 结束记录]

如评论中所述,cppreference page列出了更多标记为“自C ++ 17以来”的排序规则。这是基于n4606,最新发布的C ++ 17草案。因此,对于C ++ 17,可能不再允许这个顺序。

答案 1 :(得分:2)

另一种看待它的方式:

在开始评估a或b之前,评估x和y都没有任何好处。事实上,会有一个惩罚。额外的中间结果必须暂时保存在需要额外堆栈推送/弹出的地方,或者消耗额外的CPU寄存器(过度使用会导致额外的堆栈操作)。虽然对于您提供的示例可能影响很小或没有影响,但更复杂的案例会显示效率低下。

该规则可被视为最可能的评估,即在需要之前不进行评估,以避免携带额外的临时结果。