我可以参考初始化列表的先前成员吗?

发布于 2025-01-19 14:08:46 字数 245 浏览 0 评论 0 原文

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

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

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

Say I want to refer to a member of an initializer_list that I already defined. Can I do it?

This code compiles and gives the expected: "13 55 " in both Visual Studio and gcc, I'd just like to know that it's legal:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

微凉 2025-01-26 14:08:46

因此,我们在这里拥有的是C ++标准草案的 8.5.1 中介绍的汇总初始化,并说:

聚合是数组或类[...]

的类

和:

当指定的初始化列表初始化聚合时
在8.5.4中,初始化列表的元素被视为
汇总成员的初始化器增加下标
或会员订单。每个成员都是从
相应的初始化器条款[...]

尽管似乎合理的是初始化骨料的每个成员的副作用应在下一个之前进行测序,因为初始化器列表中的每个元素都是完整的表达式。该标准实际上并不能保证这一点,我们可以从说:

当前的措辞并不表示非阶级对象的初始化是一种全表达,但大概应该这样做。

还要注意:

汇总初始化也可能涉及多个全表达,因此上述“非阶级对象的初始化”的限制是不正确的。

我们可以从相关的理查德·史密斯说:

[intro.execution] p10:“全表达是一种表达式不是
另一个表达的子表达。 [...]如果语言构造
被定义为产生一个函数的隐式调用,
语言构造被认为是目的的表达
这个定义。”

由于支撑列表不是表达式,在这种情况下
不会导致函数调用,5和SI是独立的
全表达。然后:

[Intro.Execution] p14:“每个值计算和副作用
在每个值之前对与全表达相关联
与下一个全表达相关的计算和副作用
要评估。”

所以唯一的问题是,初始化Si的副作用
“与“全表达”的评估相关联” 5?我认为
唯一合理的假设是:如果5初始化
班级类型的成员,构造函数的调用显然是
[Into.Excution] P10中的定义的全表达,因此
自然假设标量类型也是如此。

但是,我认为该标准实际上并没有明确说明
任何地方。

因此,目前尚未由标准指定,不能依靠这一点,尽管如果一个实现未按照您的期望来对待它,我会感到惊讶。

对于这样的简单情况,与此类似的简单情况似乎是一种更好的选择:

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

C ++ 17

提案p0507r0:核心问题1343:非阶级初始化的测序澄清提出的完整表达点在这里全表达的评估。因此,这并没有改变这是未指定的。

这个问题的相关更改在 [Into.execution]

成分表达式定义如下:

(9.1) - 表达式的组成表达是表达式。

(9.2) - 支撑列表或(可能是括号的)表达列表的成分表达式是
各个列表元素的组成表达式。

(9.3) - form = initializer-clause的支架或平等仪的组成表达式是

[示例:

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

用于B的初始化的初始化器的成分表达式为5和1+1 。 - 末尾示例]

[Into.execution] p12

全表达是

(12.1) - 未评估的操作数(第8条),

(12.2) - 恒定表达(8.20),

(12.3) - init-der-darator(第11条)或孟燃剂(15.6.2),包括构成表达式
初始化器,

(12.4) - 临时物体生命周末生成的灾难的调用
对象(15.2)或

(12.5) - 不是另一个表达的亚表达的表达,否则不是一个
全表达。

因此,在这种情况下em>。这是从认为他们每个人都是自己的全表达。

C ++ 20的更改

指定的初始化建议:p0329 包含以下添加的添加,似乎可以很好地定义:

将新段落添加到11.6.1 [dcl.init.aggr]:

按元素顺序评估聚合元素的初始化。那是,
所有值计算和与给定元素相关的副作用均已在按顺序遵循的任何元素的元素之前进行测序。

我们可以看到这反映在最新草稿标准中。

So what we have here is aggregate initialization covered in section 8.5.1 of the draft C++ standard and it says:

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

and:

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 [...]

Although it seems reasonable that side effects from initializing each member of the aggregate should be sequenced before the next, since each element in the initializer list is a full expression. The standard does not actually guarantee this we can see this from defect report 1343 which says:

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

and also notes:

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

and we can see from a related std-discussion topic Richard Smith says:

[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.

So this is currently not specified by the standard and can not be relied upon, although I would be surprised if an implementation did not treat it the way you expect.

For a simple case like this something similar to this seems a better alternative:

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

Changes In C++17

The proposal P0507R0: Core Issue 1343: Sequencing of non-class initialization clarifies the full-expression point brought up here but does not answer the question about whether the side-effect of initialization is included in the evaluation of the full-expression. So it does not change that this is unspecified.

The relevant changes for this question are in [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 ]

and [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.

So in this case both 13 and foo[0] + 42 are constituent expression which are part of a full-expression. This is a break from the analysis here which posited that they would each be their own full-expressions.

Changes In C++20

The Designated Initialization proposal: P0329 contains the following addition which seems to make this well defined:

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.

We can see this is reflected in the latest draft standard.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文