我可以引用初始化列表的先前成员吗?

Can I Reference Previous Members of an Initializer List?

假设我想引用我已经定义的 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 Richard Smith 中看到:

[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 clarifies the full-expression point brought up 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 都是 组成表达式 ,它们是 完整表达式 [=63] 的一部分=].这是对 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.

我们可以看到这反映在 latest draft standard