当序列点应用于构造函数时,括号内的初始值设定项列表中是否有序列点? 根据N429 6 C++标准文件:
[dcl初始列表](8.5.4.4)(第223-224页) 在带括号的init列表的初始值设定项列表中 初始值设定项子句,包括由包扩展产生的任何 (14.5.3),按照其出现的顺序进行评估。就是, 与给定值相关的每个值计算和副作用 初始值设定项子句在每次值计算和 与中的任何初始值设定项子句相关的副作用 初始值设定项列表的逗号分隔列表。[注:此 无论函数的语义如何,求值顺序都保持不变 初始化;例如,当 初始值设定项列表被解释为构造函数调用的参数, 即使通常在 调用的参数。-结束注释] (强调矿山) 此处添加了注释: 这对我来说意味着以下代码:当序列点应用于构造函数时,括号内的初始值设定项列表中是否有序列点? 根据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),按照其出现的顺序进行评估。就是, 与给定值相关的每个值计算和副作用 初始值设定项子句在每次值计算和 与中的任何初始值设定项子句相关的副作用 初始值设定项列表的逗号分隔列表。[注:此 无论函数的语义如何,求值顺序都保持不变 初始化;例如,当 初始值设定项列表被解释为构造函数调用的参数, 即使通常在 调用的参数。-结束注释] (强调矿山)
#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