【问题标题】: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?

标签: c++ gcc operator-precedence


【解决方案1】:

这不是 braced-init-list,因此该规则不适用。

[C++14: 5.17/9]:braced-init-list 可能出现在

的右侧
  • 对标量的赋值,在这种情况下,初始化列表最多只能有一个元素。 x={v} 的含义,其中T 是表达式x 的标量类型,是x=T{v} 的含义。 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 argumentFolds (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 -Wextragcc -Wall -Wextra -std=c++11)。

【讨论】:

  • 我在任何情况下都尝试过结果是相同的问题没有添加--std=c++11
  • @user5905343 不幸的是,gcc.godbolt.org 上缺少 gcc v4.8.4,但考虑到上述测试,这似乎是一个错误。
猜你喜欢
  • 1970-01-01
  • 2012-02-16
  • 2017-02-15
  • 2012-03-19
  • 2020-11-29
  • 1970-01-01
  • 2010-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多