编译器是否允许在不同的函数参数内交错计算子表达式
Is the compiler allowed to interlace the evaluation of subexpressions within different function arguments?
我想知道以下情况:
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()
-> y()
-> a()
-> 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
,但这当然没有告诉我任何关于标准要求的东西。如果能得到标准的参考就好了。
在c++ 14及更早的版本中,x -> y -> a -> b
是可能的。这里的排序关系为:
- 呼叫
x
在呼叫a
之前排序。 - 呼叫
y
在呼叫b
之前排序。 - 呼叫
a
在呼叫f
之前排序。 - 呼叫
b
在呼叫f
之前排序。
订单上没有其他限制。如果你想执行一些特定的排序,那么你必须将这个调用分解成多个完整表达式。
在c++ 14标准中,[expr.call]/8: 说明了这个意图。[注意:后缀表达式的求值和参数的求值都是相对于彼此不排序的。在进入函数之前,对参数求值的所有副作用进行排序。- 结束说明]
如注释中所述,cppreference页面列出了一些标记为"自c++ 17以来"的排序规则。这是基于n4606, c++ 17最新发布的草案。因此,在c++ 17中,这个顺序可能不再被允许。
从另一个角度来看:
在开始计算a或b之前同时求值x和y是没有好处的。事实上,会有惩罚。额外的中间结果必须临时保存在某个地方,这可能需要额外的堆栈push/pop,或者消耗额外的CPU寄存器(过度使用会导致额外的堆栈操作)。虽然这对于您提供的示例来说可能没有什么影响,但更复杂的情况会揭示效率低下。
该规则可以被视为最懒惰的求值,即直到需要时才执行求值,以避免携带额外的临时结果。
相关文章:
- 模板参数列表中的 false 在模板初始化期间计算为什么?
- 编译器是否强制根据模板参数计算表达式?
- 有没有办法计算函数内arry的长度而不是作为参数传入?
- 返回一个计算了参数的函数
- 术语的计算结果不是采用0个参数的函数
- 错误 C2064:术语的计算结果不是采用 3 个参数的函数
- 错误:一元"*"的类型参数无效(具有"int"):使用 mergesort 计算
- 委派的 ctor 是否受参数计算顺序的影响?
- 函数参数计算顺序与 Lambda 捕获评估顺序
- 大括号和括号之间的参数计算顺序
- 使用引用参数计算函数
- 编译时的模板参数计算
- 在 x86-64 平台上为 C(++) 中的 64 位无符号参数计算 (a*b)%n FAST
- 具有参数计算错误的重载函数
- 模板参数计算
- 根据其他参数计算模板参数的惯用方法
- 移动语义和参数计算顺序
- 惰性参数计算
- C++ 参数计算顺序
- 参数计算和未定义行为