C++11中初始化列表的求值顺序

10
在下面的代码中,是必须先调用 f1 再调用 f2(或者反过来),还是没有规定先后顺序?
int f1();
int f2();

std::initializer_list<int> list { f1(), f2() };

1
f1 将首先被调用。顺便说一下,这是 cppquiz.org 上的一个问题。你可能会在那里的答案中找到相关的标准片段。 - chris
1个回答

11

这是 C++ 标准中一个非常有趣的角落,其中执行顺序被明确定义。第 8.5.4 节 [dcl.init.list],第 4 段:

在大括号初始化列表的初始化器列表内,包括任何由打包扩展 (14.5.3)生成的初始化器子句,按它们出现的顺序进行评估。也就是说,与给定初始化器子句相关联的每个值计算和副作用都在逗号分隔的初始化器列表中跟随它的任何初始化器子句相关联的每个值计算和副作用之前。

因此,在初始化器列表中,函数调用从左到右依次进行评估。


1
仅为完整起见,值得注意的是,这与 h(f1(),f2()) 形成了直接对比,其中顺序是未指定的(还有更多可能导致错误的潜在顺序,例如 h(f1(), f2(new X())),其中 new X() 可能会被评估,然后调用 f1() 并引发异常,因此 X 被泄漏...) - Michael Anderson
1
@MichaelAnderson:嗯,没错。它只适用于初始化列表。但这正是问题所在。我试图暗示行为异常明确定义了。(内置逗号运算符也指定了评估顺序,但不像你所说的那样针对函数调用中的参数。) - rici
1
我在思考C++11之前的区别,以前我可能会使用可变参数或者重载的方式来调用一个接受多个int参数的函数,例如fn(f1(),f2(),f3()),需要注意参数的顺序。但是在C++11中,我可以使用初始化列表fn( { f1(), f2(), f3() } ),并且参数的顺序是有保证的。当然,初始化列表还有更多的用途。 - Michael Anderson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接