这个问题是关于C++0x中是否允许对未知大小的数组进行列表初始化。
int main() { int x[]{0, 1,2,3,4}; return x[0]; }
我认为这是有效的,但希望得到确认。
如果有人能够引用C++0x-FCD来支持他们的观点,那将不胜感激。
谢谢!
int main() { int x[]{0, 1,2,3,4}; return x[0]; }
我认为这是有效的,但希望得到确认。
如果有人能够引用C++0x-FCD来支持他们的观点,那将不胜感激。
谢谢!
8.5/16
的第一个项目到8.5.4
的列表初始化,再从8.5.4/3
的第三个项目到8.5.1
的聚合初始化,然后8.5.1/4
表明:
用括号括起来的初始化列表初始化未知大小的数组,该列表包含n个初始化子句,其中应大于零,定义为具有元素
如果对象是数组,则= {...}
和{...}
之间唯一的区别在于前者称为复制列表初始化,后者称为直接列表初始化,因此两者都是列表初始化的一种。在两种情况下,数组的元素都是从初始化列表的元素进行复制初始化。
请注意,如果数组有大小并且列表为空,则这些形式之间存在微妙的差异,在这种情况下,应用8.5.4
的第二个项目:
struct A {
explicit A();
};
A a[1]{}; // OK: explicit constructor can be used by direct initialization
A a[1] = {}; // ill-formed: copy initialization cannot use explicit constructor
如果列表中有内容,则不适用这种差异,此时第三个项目符号再次适用。
struct A {
explicit A(int);
};
A a[1]{0}; // ill-formed: elements are copy initialized by 8.5.1
A a[1] = {0}; // ill-formed: same.
与先前的草案相比,FCD对此进行了更改,并且使用空的初始化列表进行初始化现在始终可以正常工作,即使使用显式默认构造函数也是如此。这是因为FCD声明的元素是值初始化的,而值初始化不关心显式性,因为它不会在默认构造函数上执行重载决议(无论如何都无法找到更好或更差的匹配项)。先前的草案在构造函数上使用正常的重载决议,因此在复制初始化期间拒绝显式默认构造函数。 这个缺陷报告做出了这个变化。
是的,它是有效的,甚至在C语言中也是如此,大小只需设置为提供的元素数量即可。不幸的是,我不知道参考文献。
(额外加分...) 如果您需要元素的数量,请使用sizeof(x)/sizeof(*x)
。这比硬编码可能因添加或删除条目而失效的常量更安全。
编辑:正如评论中指出的那样,所讨论的代码缺少一个=
(我错过了这一点),没有它,在当前的C或C++标准中都是无效的。
explicit A(int = 0);
也是一个显式的默认构造函数。因此,这个改变可能会影响更多的程序,比人们最初想象的要多。但我认为FCD的行为更有益,因为“explicit”并没有真正涉及默认构造,而更多地涉及参数转换 :) - Johannes Schaub - litbint(&&arr)[] = { 0 }
,我们有“否则,如果初始化列表只有一个元素,则从该元素初始化对象;”但是这听起来很奇怪,因为它似乎暗示这种情况只能发生在对象上,但实际上在这种情况下它发生在引用上。无论如何,如果我们将“对象”替换为“对象或引用”,那么它会尝试执行int(&&arr)[] = 0;
,同样是不合法的。所以无论如何,你都不能这样做,但似乎标准对数组引用并没有好好考虑。 - Johannes Schaub - litb