【发布时间】:2011-02-06 11:59:34
【问题描述】:
这个未知大小数组的列表初始化在 C++0x 中有效吗?
int main() { int x[]{0, 1,2,3,4}; return x[0]; }
我相信它是有效的,但希望得到一些确认。
如果有人可以引用C++0x-FCD 来支持他们的案例,我们将不胜感激。
谢谢!
【问题讨论】:
标签: c++ arrays initialization c++11
这个未知大小数组的列表初始化在 C++0x 中有效吗?
int main() { int x[]{0, 1,2,3,4}; return x[0]; }
我相信它是有效的,但希望得到一些确认。
如果有人可以引用C++0x-FCD 来支持他们的案例,我们将不胜感激。
谢谢!
【问题讨论】:
标签: c++ arrays initialization c++11
这从8.5/16 第一个项目符号到8.5.4 列表初始化,从8.5.4/3 第三个项目符号到8.5.1 聚合初始化,然后8.5.1/4 说
一个大小未知的数组,用一个包含n个初始化子句的大括号括起来的初始化列表初始化,其中应大于零,被定义为具有元素
如果对象是= { ... } 和{ ... } 之间的数组,唯一的区别是第一个称为copy-list-initialization,第二个称为direct-list-初始化,所以两者都是列表初始化。在这两种情况下,数组的元素都是从初始化列表的元素复制初始化的。
请注意,如果数组有大小且列表为空,则这些形式之间存在细微差别,在这种情况下,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 声明元素是值初始化的,并且值初始化不关心显式性,因为它不会对默认构造函数进行重载解析(无论如何它无法确定更好或更差的匹配)。之前的草案在构造函数上使用了正常的重载决议,因此在复制初始化期间拒绝了显式的默认构造函数。 This defect report 进行了更改。
【讨论】:
explicit A(int = 0); 也是一个显式的默认构造函数。因此,这种变化可能会影响比人们最初想象的更多的程序。但我认为 FCD 的行为更有益,因为“显式”并没有真正说明默认构造,而是更多关于参数转换:)
int(&&arr)[] = {}; 还有一些其他情况,它会命中“...或者如果 T 是任何引用类型并且初始化列表没有元素”,但它的格式不正确,因为它试图构造一个零元素数组。
int(&&arr)[] = { 0 },我们有“否则,如果初始化列表只有一个元素,则从该元素初始化对象;”然而这听起来很奇怪,因为它似乎暗示这种情况只能发生在对象上,但实际上在这种情况下它发生在引用上。在任何情况下,如果我们用“对象或引用”替换“对象”,那么它会尝试执行int(&&arr)[] = 0;,这同样是格式错误的。所以在任何情况下,你都不能这样做,但标准似乎对数组引用没有深思熟虑。
是的,它是有效的,并且已经存在了几十年,即使在 C 中也是如此。大小只是设置为提供的元素数量。不幸的是,我不知道参考文献。
(额外奖励...)如果您需要元素数量,请使用sizeof(x)/sizeof(*x)。这比硬编码一个在添加或删除条目时可能变得无效的常量更安全。
编辑:正如 cmets 中所指出的,有问题的代码缺少 =(我错过了这个事实),没有它,它在任何当前的 C 或 C++ 标准中都无效。
【讨论】: