c++ - 我可以引用初始值设定项列表的先前成员吗?

标签 c++ arrays language-lawyer initializer-list aggregate-initialization

假设我想引用我已经定义的 initializer_list 的成员。可以吗?

此代码在 Visual Studio 和 gcc 中编译并给出预期的:“13 55” ,我只想知道这是合法的:

const int foo[2] = {13, foo[0] + 42};

最佳答案

所以我们在这里看到的是 C++ 标准草案 8.5.1 部分中介绍的聚合初始化,它说:

An aggregate is an array or a class [...]

和:

When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause [...]

虽然初始化聚合的每个成员的副作用应该在下一个之前排序似乎是合理的,因为初始化列表中的每个元素都是一个完整的表达式。标准实际上并不能保证这一点,我们可以从 defect report 1343 中看到这一点。其中说:

The current wording does not indicate that initialization of a non-class object is a full-expression, but presumably should do so.

还有注意事项:

Aggregate initialization could also involve more than one full-expression, so the limitation above to “initialization of a non-class object” is not correct.

我们可以从相关的 std-discussion topic 中看到理查德史密斯说:

[intro.execution]p10: "A full-expression is an expression that is not a subexpression of another expression. [...] If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition."

Since a braced-init-list is not an expression, and in this case it does not result in a function call, 5 and s.i are separate full-expressions. Then:

[intro.execution]p14: "Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated."

So the only question is, is the side-effect of initializing s.i "associated with" the evaluation of the full-expression "5"? I think the only reasonable assumption is that it is: if 5 were initializing a member of class type, the constructor call would obviously be part of the full-expression by the definition in [intro.execution]p10, so it is natural to assume that the same is true for scalar types.

However, I don't think the standard actually explicitly says this anywhere.

因此,目前标准并未对此进行规定,也不能依赖它,尽管如果实现没有按照您期望的方式处理它,我会感到惊讶。

对于像这样的简单情况,类似这样的东西似乎是更好的选择:

constexpr int value = 13 ;
const int foo[2] = {value, value+42};

C++17 的变化

proposal P0507R0: Core Issue 1343: Sequencing of non-class initialization阐明提出的完整表达点here但没有回答关于初始化的副作用是否包含在完整表达式的评估中的问题。所以这并没有改变,这是未指定的。

此问题的相关更改位于 [intro.execution] :

A constituent expression is defined as follows:

(9.1) — The constituent expression of an expression is that expression.

(9.2) — The constituent expressions of a braced-init-list or of a (possibly parenthesized) expression-list are the constituent expressions of the elements of the respective list.

(9.3) — The constituent expressions of a brace-or-equal-initializer of the form = initializer-clause are the constituent expressions of the initializer-clause. [ Example:

struct A { int x; };
struct B { int y; struct A a; };
B b = { 5, { 1+1 } };

The constituent expressions of the initializer used for the initialization of b are 5 and 1+1. —end example ]

[intro.execution]p12 :

A full-expression is

(12.1) — an unevaluated operand (Clause 8),

(12.2) — a constant-expression (8.20),

(12.3) — an init-declarator (Clause 11) or a mem-initializer (15.6.2), including the constituent expressions of the initializer,

(12.4) — an invocation of a destructor generated at the end of the lifetime of an object other than a temporary object (15.2), or

(12.5) — an expression that is not a subexpression of another expression and that is not otherwise part of a full-expression.

所以在这种情况下,13foo[0] + 42 都是 constituent expression,它们是 full-表达式。这是 analysis here 的中断。假设它们每个都是自己的完整表达式。

C++20 的变化

Designated Initialization proposal: P0329包含以下添加内容,似乎可以很好地定义:

Add a new paragraph to 11.6.1 [dcl.init.aggr]:

The initializations of the elements of the aggregate are evaluated in the element order. That is, all value computations and side effects associated with a given element are sequenced before those of any element that follows it in order.

我们可以看到这反射(reflect)在 latest draft standard .

关于c++ - 我可以引用初始值设定项列表的先前成员吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33828350/

相关文章:

c++ - 如何重载模板函数以匹配特定容器?

c - 如果对于 &*x 不评估 * 和 &,那么为什么不对 *&x 采用相同的规则呢?

c++ - 初始化数组,放置新的,读取变量,定义行为?

javascript - 递归数据结构将每个分支分开

c++ - 无法识别 main() 函数

c++ - 为什么我的默认构造函数返回一个 boolean 值?

c++ - cpp程序在访问类成员的成员变量时挂起

c++ - 在没有管理员权限的情况下安装 Qt

arrays - Bigquery - 如何将两个数组压缩为一个?

java - 字符串数组的 ArrayList 只保存最后一条记录