首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >当有括号的初始化器列表应用于构造函数时,它们中是否有序列点?

当有括号的初始化器列表应用于构造函数时,它们中是否有序列点?
EN

Stack Overflow用户
提问于 2016-04-26 06:41:33
回答 2查看 830关注 0票数 23

根据n4296 C++标准文档:

dcl.init.list (pg223-224)

在带括号的init-list的initializer-list中,initializer-子句,包括任何由包扩展(14.5.3)产生的子句,按照它们出现的顺序进行计算。也就是说,在初始化器列表的逗号分隔列表中,与给定的初始化器子句相关联的每个值计算和副作用在与它后面的任何初始化器子句相关联的每个值计算和副作用之前被排序。注意:无论初始化的语义如何,这种求值顺序都有效;例如,当初始化器列表的元素被解释为构造函数调用的参数时,即使通常对调用的参数没有排序约束,它也适用。-end笔记

(强调我的)

注释添加到这里:http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1030

在我看来,下面的代码:

代码语言:javascript
复制
#include <iostream>

struct MyType {
  MyType(int i, int j, int k, int l)
    : sum(i + j + k + l)
  {

  }

  int sum;
};

int main()
{
  int i = 0;
  std::cout << MyType{ ++i, ++i, ++i, ++i }.sum << '\n';
}

应打印"10“。

这是我的理由:

正在通过braced-init-list

  • braced-init-lists进行初始化的MyType(1,2,3,4)

are evaluated in

  • ,即使它被解释为调用
  • 的构造函数的参数,这也意味着它应该被计算为MyType(1,2,3,4)

也就是说,上面的代码应该与下面的代码完全一样:

代码语言:javascript
复制
#include <initializer_list>
#include <iostream>

int main()
{
  int i = 0;
  std::initializer_list<int> il{++i, ++i, ++i, ++i};
  std::cout << *il.begin() + *(il.begin() + 1) + *(il.begin() + 2) + *(il.begin() + 3) << '\n';
}

但事实并非如此。第一个示例打印'16‘,第二个示例打印'10’

从字面上看,我能得到的来自每个供应商的每个编译器都打印了'16',似乎忽略了标准的这一部分,也没有插入序列点。

这里我漏掉了什么?

注意:以下内容似乎与此问题相关:

EN

回答 2

Stack Overflow用户

发布于 2016-07-05 22:26:47

答案似乎是肯定的,这是一个错误,在GCC和MSVC。

这是此问题的状态:

  1. 关于初始化列表规则,有几个关于GCC的bug。他们中的大多数都完全没有得到GCC团队的认可。这至少意味着G++在这里确实有错误,因为这些问题并没有作为无效的
  2. 关闭。我收到来自MSVC编译器团队的非官方消息,这实际上是他们编译器中的一个错误,他们正在内部工作来修复它。但是,我没有外部bug可以指出。从MSVC2015更新3开始,旧的behavior remains.
  3. Clang,在这一点上是迄今为止最书生气的标准兼容编译器,它以标准阅读的方式实现它。

我个人的调查,在会议上与C++专家的讨论,以及我从编译器开发人员那里得到的非官方答案表明,这是MSVC和GCC的一个错误,但我总是不愿回答我自己在StackOverflow上的问题。但我们还是来了。

票数 7
EN

Stack Overflow用户

发布于 2016-07-04 01:42:58

此说明与评估顺序无关。正如其中一条注释所述,这是关于将实际参数转换为右值的顺序,而标准并没有定义这种顺序。您应该收到以下警告(gcc):

代码语言:javascript
复制
17:58: warning: operation on 'i' may be undefined [-Wsequence-point]

我稍微修改了一个程序,演示了参数求值如何使用{}和()。

通过这样的修改,程序不依赖于左值到右值的转换顺序,因此没有让你失望的歧义。

代码语言:javascript
复制
#include <iostream>

struct MyType {
  MyType(int i, int j)
    : sum(i + j)
  {

  }

  int sum;
};

int main()
{
  int i = 0;
  int a,b;
  std::cout << MyType{ (a = ++i), (b = ++i) }.sum << '\n';
  std::cout << "Here clauses are evaluated in order they appear: a=" << a << ", b=" << b << std::endl;
  i = 0;
  std::cout << MyType( (a = ++i), (b = ++i) ).sum << '\n';
  std::cout << "Here order of evaluation depends on implementation: a=" << a << ", b=" << b << std::endl;
}

对于clang和gcc,该程序的输出为:

当当:

代码语言:javascript
复制
3
Here clauses are evaluated in order they appear: a=1, b=2
3
Here order of evaluation depends on implementation: a=1, b=2

gcc:

代码语言:javascript
复制
3
Here clauses are evaluated in order they appear: a=1, b=2
3
Here order of evaluation depends on implementation: a=2, b=1

正如您所看到的,在花括号的情况下,子句在两个编译器中的出现顺序都是计算的,这与您提供的注释相对应。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36852367

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档