假设我想引用已定义的initializer_list
的成员,我能做到吗?
在Visual Studio和gcc中,此代码编译并输出预期结果:"13 55 ",我只是想知道它是否合法:
const int foo[2] = {13, foo[0] + 42};
假设我想引用已定义的initializer_list
的成员,我能做到吗?
在Visual Studio和gcc中,此代码编译并输出预期结果:"13 55 ",我只是想知道它是否合法:
const int foo[2] = {13, foo[0] + 42};
这里涉及到C++标准草案中的第8.5.1
节中介绍的聚合初始化:
聚合体是指数组或类[...]
以及:
当使用初始化器列表(如8.5.4所规定)对聚合体进行初始化时,初始化器列表中的元素将按照下标或成员顺序递增作为聚合体成员的初始化器。每个成员都从相应的初始化器子句中进行复制初始化[...]
尽管似乎合理的是,从初始化聚合体的每个成员中产生的副作用应该在下一个成员之前被排序,因为初始化列表中的每个元素都是完整的表达式。但标准实际上并没有保证这一点,我们可以从defect report 1343中看到这一点,其中指出:
当前措辞并未表明非类对象的初始化是完整表达式,但可能应该这样做。
同时也注意到:
聚合初始化也可以涉及多个完整表达式,因此上述对“非类对象的初始化”的限制是不正确的。另外,我们可以从相关的std-discussion topic中看到Richard Smith的说法:constexpr int value = 13 ;
const int foo[2] = {value, value+42};
提案P0507R0:核心问题1343:非类初始化的顺序澄清了此处提出的完整表达点,但并未回答初始化的副作用是否包含在完整表达式的评估中的问题。因此,这仍然是未指定的。
这个问题的相关变化在[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 ]
在这种情况下,完整表达式是
(12.1) — 未求值的操作数 (第8条款),
(12.2) — 常量表达式 (8.20),
(12.3) — 初始化声明符 (第11条款) 或成员初始化器 (15.6.2),包括初始化器的组成表达式,
(12.4) — 在非临时对象的生命周期结束时生成的析构函数调用 (15.2), 或
(12.5) — 不是另一个表达式的子表达式且不属于完整表达式的其他部分的表达式。
13
和foo[0] + 42
都是一个完整表达式的组成部分。这与此处的分析不同,该分析认为它们各自都是完整表达式。
指定初始化提案:P0329包含以下补充,似乎使得这个定义良好:
向11.6.1 [dcl.init.aggr]添加新的段落:
聚合体元素的初始化按照元素顺序进行评估。也就是说,与给定元素相关的所有值计算和副作用在其后面的任何元素之前进行排序。
我们可以看到这在最新的标准草案中有所反映。
P0329
的更改说明了“元素的初始化”,然后又说“与聚合体的给定元素相关的值计算和副作用”这与 [dcl.init.list]p4
不同,后者涉及到“初始化器子句”及其相关影响。 - Shafik Yaghmour
initializer_list
,对吗? - Baum mit Augen