说我想引用我已定义的initializer_list
成员。我可以这样做吗?
此代码编译并给出预期的:" 13 55"在Visual Studio和gcc中,我只是想知道它是合法的:
const int foo[2] = {13, foo[0] + 42};
答案 0 :(得分:20)
所以我们这里有C ++标准草案8.5.1
部分所述的聚合初始化,它说:
聚合是数组或类[...]
和
按指定的初始化列表初始化聚合时 在8.5.4中,初始化列表的元素被视为 增加下标的聚合成员的初始化程序 或会员订单。每个成员都是从中复制初始化的 相应的初始化条款[...]
虽然初始化聚合的每个成员的副作用应该在下一个之前进行排序似乎是合理的,因为初始化列表中的每个元素都是完整表达式。该标准实际上并不能保证我们可以从defect report 1343看到这一点:
当前的措辞并不表示非类对象的初始化是一个完整表达式,但可能应该这样做。
还注意到:
聚合初始化也可能涉及多个完整表达式,因此上面对“非类对象的初始化”的限制是不正确的。
我们可以从相关的std-discussion topic Richard Smith看到:
[intro.execution] p10:"完整表达式是不是的表达式 另一个表达式的子表达式。 [...]如果是语言结构 定义为生成函数的隐式调用,使用 语言结构被认为是出于此目的的表达 这个定义。"
因为braced-init-list不是表达式,在这种情况下就是它 不会导致函数调用,5和s.i是分开的 全表达式。然后:
[intro.execution] p14:"每个值计算和副作用 在每个值之前对与完整表达相关联的序列进行排序 与下一个完整表达式相关的计算和副作用 待评估。"
所以唯一的问题是,初始化s.i的副作用是什么 "与"相关联评价全面表达" 5"?我认为 唯一合理的假设是:如果5正在初始化a 类类型的成员,构造函数调用显然是其中的一部分 [intro.execution] p10中定义的完整表达式,所以它 很自然地假设标量类型也是如此。
但是,我并不认为该标准实际明确地说明了这一点 任何地方。
所以这个标准目前没有规定,不能依赖,但如果实施没有像你期望的那样对待它,我会感到惊讶。
对于像这样的简单案例,类似的事情似乎是一个更好的选择:
constexpr int value = 13 ;
const int foo[2] = {value, value+42};
proposal P0507R0: Core Issue 1343: Sequencing of non-class initialization澄清了here提出的完整表达点,但没有回答关于初始化的副作用是否包含在全表达式评估中的问题。所以它没有改变,这是未指定的。
此问题的相关更改位于[intro.execution]:
构成表达式定义如下:
(9.1) - 表达式的组成表达式是表达式。
(9.2) - braced-init-list或(可能带括号的)表达式列表的组成表达式是 相应列表元素的组成表达。
(9.3) - form = initializer-clause的大括号或等于初始化程序的组成表达式是 初始化子句的组成表达。 [例如:
struct A { int x; }; struct B { int y; struct A a; }; B b = { 5, { 1+1 } };
用于初始化b的初始化器的组成表达式是5和1 + 1 。 - 例子]
完整表达是
(12.1) - 未评估的操作数(第8条),
(12.2) - 常量表达式(8.20),
(12.3) - init-declarator(第11条)或mem-initializer(15.6.2),包括 初始化,强>
(12.4) - 在临时对象的生命周期结束时生成的析构函数的调用 对象(15.2)或
(12.5) - 一个表达式,它不是另一个表达式的子表达式,而不是一个表达式的子表达式 全表达。
因此,在这种情况下,13
和foo[0] + 42
都是组成表达式,它们是完整表达式的一部分。这是analysis here的一个突破,它假定每个人都是他们自己的完整表达。
Designated Initialization proposal: P0329包含以下添加内容,似乎可以很好地定义:
在11.6.1 [dcl.init.aggr]中添加一个新段落:
聚合元素的初始化按元素顺序进行评估。那是, 与给定元素相关的所有值计算和副作用在按顺序跟随它的任何元素之前排序。
我们可以看到这反映在latest draft standard。
中