初始化列表中元素的求值顺序
Posted
技术标签:
【中文标题】初始化列表中元素的求值顺序【英文标题】:Evaluation order of elements in an initializer list 【发布时间】:2016-05-16 13:13:25 【问题描述】:为什么首先调用函数g()
?我将g()
定义为初始化列表中的第二个元素。
以下与初始化列表相关的标准引用是否相关?
§8.5.4.4:在花括号初始化列表的初始化列表中, 初始化子句,包括任何由包扩展产生的子句 (§14.5.3),按照它们出现的顺序进行评估。
#include <iostream>
#include <vector>
int f() std::cout << "f"; return 0;
int g() std::cout << "g"; return 0;
void h(std::vector<int> v)
int main()
h(f(), g());
输出:
gf
【问题讨论】:
您的代码不包含任何初始化列表。 C++ 中未指定函数参数的求值顺序。 所有评论和重复投票者请注意:OP 没有调用带有两个参数的函数,OP 正在调用带有 one 参数的函数,这是一个初始化的向量使用统一初始化和向量的std::initializer_list
构造函数。
你是运行了编辑帖子中的代码,还是这是之前版本的结果?
您使用的是哪个版本的 GCC?
【参考方案1】:
这不是 braced-init-list,因此该规则不适用。
的右侧 对标量的赋值,在这种情况下,初始化列表最多只能有一个元素。
[C++14: 5.17/9]:
braced-init-list 可能出现在x=v
的含义,其中T
是表达式x
的标量类型,是x=Tv
的含义。x=
的含义是x=T
。 对类类型对象的赋值,在这种情况下,初始化列表作为参数传递给由重载决策(13.5.3、13.3)选择的赋值运算符函数。
【讨论】:
可能我错了,但 braced-init-list 可能会出现在许多其他情况下:例如for-range-initializer (for (for-range-declaration: braced-init-list) statement
, §6.5.4), jump-statements (return braced-init-list;
, §6.6), ...
@manlio:嗯,好吧,我确实试图找到 this 案例没有 braced-init-list 的证据它(这将是一个更好的答案)但得出的结论是我不得不引用太多。
还考虑到std::initializer_list as function argument,尤其是this answer,参数传递应该与=
初始化器具有相同的含义(两者都是复制初始化)。那么这不是复制初始化(对象 list-initialized via braced-init-list)吗?
@manlio:现在没有时间调查。随意写一个答案:)【参考方案2】:
在我看来引用是相关的(编译器看到一个初始化列表):
8.5/14,16:
表单中发生的初始化
T x = a;
以及在参数传递中、函数返回、抛出异常 (15.1)、处理异常 (15.3) 和聚合成员初始化 (8.5.1) 称为复制初始化。
.
.
初始化器的语义如下[...]:如果初始化器是一个花括号初始化列表,则对象是列表初始化的(8.5.4)。
(更多细节在std::initializer_list as function argument和Folds (ish) In C++11)
此外,任何-list 都应该被排序(该标准对这一事实使用了非常强烈的措辞。另见http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1030)。
所以它是probably a GCC bug(在 gcc v4.9.0 之后修复)。
确实,尝试了各种 GCC 版本,我得到了:
GCC with --std=c++11 without (--std=c++98)
4.7.3 fg gf <-
4.8.1 fg gf <-
4.8.2 fg gf <-
4.9.0 fg gf <-
4.9.2 fg fg
5.1.0 fg fg
5.2.0 fg fg
6.1.0 fg fg
扩展初始值设定项列表仅适用于 C++11,但 GCC 无论如何都会编译代码(带有警告,例如参见 gcc -Wall -Wextra
与 gcc -Wall -Wextra -std=c++11
)。
【讨论】:
我在任何情况下都尝试过结果是相同的问题没有添加--std=c++11 @user5905343 不幸的是,gcc.godbolt.org 上缺少 gcc v4.8.4,但考虑到上述测试,这似乎是一个错误。以上是关于初始化列表中元素的求值顺序的主要内容,如果未能解决你的问题,请参考以下文章
《Go语言精进之路》读书笔记 | 理解Go语言表达式的求值顺序