当序列点应用于构造函数时,括号内的初始值设定项列表中是否有序列点? 根据N429 6 C++标准文件:

当序列点应用于构造函数时,括号内的初始值设定项列表中是否有序列点? 根据N429 6 C++标准文件:,c++,c++11,gcc,visual-c++,clang,C++,C++11,Gcc,Visual C++,Clang,[dcl初始列表](8.5.4.4)(第223-224页) 在带括号的init列表的初始值设定项列表中 初始值设定项子句,包括由包扩展产生的任何 (14.5.3),按照其出现的顺序进行评估。就是, 与给定值相关的每个值计算和副作用 初始值设定项子句在每次值计算和 与中的任何初始值设定项子句相关的副作用 初始值设定项列表的逗号分隔列表。[注:此 无论函数的语义如何,求值顺序都保持不变 初始化;例如,当 初始值设定项列表被解释为构造函数调用的参数, 即使通常在 调用的参数。-结束注释] (强调矿山)

[dcl初始列表](8.5.4.4)(第223-224页)

在带括号的init列表的初始值设定项列表中 初始值设定项子句,包括由包扩展产生的任何 (14.5.3),按照其出现的顺序进行评估。就是, 与给定值相关的每个值计算和副作用 初始值设定项子句在每次值计算和 与中的任何初始值设定项子句相关的副作用 初始值设定项列表的逗号分隔列表。[注:此 无论函数的语义如何,求值顺序都保持不变 初始化;例如,当 初始值设定项列表被解释为构造函数调用的参数, 即使通常在 调用的参数。-结束注释]

(强调矿山)

此处添加了注释:

这对我来说意味着以下代码:

#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';
}
#包括
结构MyType{
MyType(整数i、整数j、整数k、整数l)
:总和(i+j+k+l)
{
}
整数和;
};
int main()
{
int i=0;

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

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

通过这样的修改,程序不依赖于将左值转换为右值的顺序,因此不会产生令您失望的歧义。

#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;
}
通用条款:


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

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

以下是此问题的状态:

  • 关于初始化列表规则,GCC有几个错误。大多数错误都没有得到GCC团队的确认。这至少意味着G++在这里确实存在错误,因为这些问题没有被视为无效而解决
  • 我收到了MSVC编译器团队的非正式消息,这实际上是他们编译器中的一个bug,他们正在内部修复它。但是,我没有外部bug可指。截至MSVC 2015更新3,旧的行为仍然存在
  • 到目前为止,Clang是最迂腐的标准投诉编译器,它以标准看起来的方式实现它

  • 我个人的调查,会议上C++专家的讨论,以及编译器开发人员所收到的非官方答案表明,这是MSVC和GCC的一个bug,但我总是不愿回答我自己关于StAdvExcel的问题。但是我们在这里。

    你尝试过哪些编译器?N429不是标准的。,这是godbolt上C++17标准化过程中的一个工作草案,所有的clang版本都给出了
    10
    ,所有的gcc版本都给出了
    16
    ,所以可能是一个gcc错误。@T.C:我从您对错误报告的评论#2中了解到这里有两个级别:(1)花括号列表中初始值设定项的求值顺序与源代码中的顺序相同,但是(2)这不一定是结果随后转换为右值的顺序?如果是这样,那么这是非常令人惊讶的行为,我认为这可能是委员会无意中发现的。也就是说,这里可能存在核心语言缺陷?不,问题具体是关于序列点,而不是评估顺序。你说:“这意味着它应该被评估为MyType(1,2,3,4)”。是的,它是这样评估的,但在评估之后构造函数被称为MyType(i,i,i,i)。您提供的注释中没有描述构造函数调用,它只是在评估中定义了顺序。因此,您有如上所述的编译警告。您似乎缺少了”注意:无论初始化的语义如何,这种求值顺序都适用;例如,当初始值设定项列表的元素被解释为构造函数调用的参数时,它适用,即使调用的参数通常没有顺序约束。-结束注原始发布的一部分,其中明确声明“构造函数调用”
    17:58: warning: operation on 'i' may be undefined [-Wsequence-point]
    
    #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;
    }
    
    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
    
    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