【发布时间】:2015-07-10 06:17:32
【问题描述】:
在下面的代码中,是否需要在f2 之前调用f1(反之亦然)还是未指定?
int f1();
int f2();
std::initializer_list<int> list { f1(), f2() };
【问题讨论】:
-
f1将首先被调用。 FWIW,这是 cppquiz.org 上的一个问题。您可能会在那里的答案中找到相关的标准部分。
在下面的代码中,是否需要在f2 之前调用f1(反之亦然)还是未指定?
int f1();
int f2();
std::initializer_list<int> list { f1(), f2() };
【问题讨论】:
f1 将首先被调用。 FWIW,这是 cppquiz.org 上的一个问题。您可能会在那里的答案中找到相关的标准部分。
这是 C++ 标准中一个有趣的角落,其中明确定义了执行顺序。第 8.5.4 节 [dcl.init.list],第 4 段:
在花括号初始化列表的初始化列表中,初始化子句,包括任何由包扩展 (14.5.3) 产生的子句,按照它们出现的顺序进行评估。也就是说,与给定初始化子句关联的每个值计算和副作用都在初始化器列表的逗号分隔列表中与任何初始化子句相关联的每个值计算和副作用之前进行排序。
所以在初始化列表中,函数调用是从左到右计算的。
【讨论】:
h(f1(),f2()) 形成直接对比,(然后还有更多错误会导致h(f1(), f2(new X())) 的潜在订单new X()可能会被评估,然后调用 f1() 并引发异常,因此 X 被泄露...)
ints 使用 vargs 或像 fn(f1(),f2(),f3()) 这样的重载,并且需要注意顺序,但是在 C++11 中,我可以使用初始化列表 fn( { f1(), f2(), f3() } ) 并保证顺序。当然,初始化列表的用途不止于此。